我要相信LA已經掛掉了
不管是我的代碼還是網上的AC代碼
交上去全是WA WA WA!!!
so。。我也不知道我寫的到底能不能過。。。以後找時間交吧。。
QAQ兩道01揹包。。當時學揹包就沒好好學T_T於是…………
Uvalive4015 Caves
題意:(不吐槽lrj那個語死早的翻譯了)就是一個人要在樹上走。。他可以在樹上隨意走動 然後有一些詢問每次給出一個x 就是他每次在樹上一共走x以內的距離(包含折返的)求最多能經過多少節點。。
由於這個x的範圍真的是比較大。。。 = = 5 * 1e6...因爲是樹上所以一定會記錄當前節點。。那麼x放到狀態裏可能有點orz。。。。
然後窩就不會了T_T 然後。。發現可以把經過節點數放到狀態裏。。然後更新距離最後二分答案T_T wocccccc竟然又是被二分卡住了。。。
dp[u][i][j][k] 表示走到了u節點 已經考慮了i個兒子 還要走j個節點 是否不折返回u 的最小距離
轉移:
dp[u][i][j][0] = min{ dp[u][i - 1][j - k][0] + dp[v][ch_sum][k][0] + 2 * e[i].w }
dp[u][i][j][1] = min{ dp[u][i - 1][j - k][0] + dp[v][ch_sum][k][1] + e[i].w, dp[u][i -1][j - k][1] + dp[v][ch_sum][k][0] + 2 * e[i].w }
(那個ch_sum就是表示兒子v的總兒子數。。)
這樣的狀態是開不下的。。。所以第二維拆掉滾動。。所以要倒序枚舉j你造吧。。。
然後就這樣吧。。昨天考試的時候順帶寫的代碼。。。讀入輸出優化佔了大部分地方T_T。。。
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int read()
{
int n = 0, sign = 1; char c = getchar();
while (c < '0' || c > '9') {if(c == '-') sign = -1; c = getchar(); }
while (c >= '0' && c <= '9') { n = n*10 + c-'0'; c = getchar(); }
return n * sign;
}
void print(int x)
{
if (x < 0) { putchar('-'); x *= -1; }
if (!x) puts("0");
else {
int bit[15], len = 0;
while (x) { bit[++len] = x % 10; x /= 10; }
for (int i = len; i; --i) putchar(bit[i] + '0');
puts("");
}
}
const int Nmax = 505;
int N, root;
int dp[Nmax][Nmax][3];
struct ed{
int v, w, next;
}e[Nmax];
int k = 1, head[Nmax];
inline void adde(int u, int v, int w)
{
e[k] = (ed){ v, w, head[u] };
head[u] = k++;
}
void dfs(int u)
{
dp[u][1][0] = dp[u][1][1] = 0;
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].v; dfs(v);
for (int j = N; j > 1; j--)
for (int k = 1; k <= j - 1; ++k)
{
dp[u][j][0] = min(dp[u][j][0], dp[u][j - k][0] + dp[v][k][0] + 2 * e[i].w);
int temp = min(dp[u][j - k][0] + dp[v][k][1] + e[i].w, dp[u][j - k][1] + dp[v][k][0] + 2 * e[i].w);
dp[u][j][1] = min(dp[u][j][1], temp);
}
}
}
int main()
{
int cas = 0; while (scanf("%d", &N) && N)
{
memset(head, 0, sizeof(head)); k = 1; bool flag[Nmax];
for (int i = 1; i < N; ++i)
{
int v = read(), u = read(), w = read();
adde(u, v, w); flag[v] = 1;
}
for (int i = 0; i < N; ++i) if (!flag[i]) { root = i; break; }
memset(dp, 0x3f, sizeof(dp)); dfs(root);
printf("Case %d:\n", ++cas);
for (int Q = read(); Q--; )
{
int x = read(), l = 1, r = N;
while (r > l)
{
int mid = (l + r >> 1) + 1;
if (dp[root][mid][1] <= x || dp[root][mid][0] <= x) l = mid;
else r = mid - 1;
}
print(l);
}
}
return 0;
}
Uvalive3637 The Bookcase
題意:&……&*¥…@(*&¥*……%*&……#@#%%……不想寫了……
最開始以爲是斜率優化。。因爲和之前那個打洞那個好像。。。後來發現不是。。。。
然後實在想不出去看了題解君。。。算了下複雜度把我嚇到了。。。。
按照題解的做法。。。複雜度是70 * (70 * 30)^ 2的。。。這個複雜度。。。真的能跑起來。。。?
好吧我們就假設它可以吧。。。。。。
先把書從大到小排序 按順序一本一本放 那麼影響h的就只有第一本書了 放之後的書都隻影響寬度了
然後就是暴力枚舉了。。。 = =枚舉三層的寬度。。不。。只用枚舉兩層。。第一層直接減一下就好了(其實感覺這樣很多狀態是沒用的吧。。但是不知道怎麼優化。。)
然後求出每種寬度的最小高度。。再求個最小值就行了。。。。。。
(這真的是dp????暴力真的不會更快????……)
首先假設第一本放在了第一層(其實具體放在哪一層不影響。。這個主要是爲了保證每層都有書)
dp[i][j][k] 表示對於前i本書 第二層寬度爲j 第三層寬度爲k的 第二層和第三層的總高度的最小值
令 w = 第i本的寬度 h = 第i本的高度。那麼轉移:
放在第二層第一本: update( dp[i][w][k], dp[i -1][0][k] + h )
放在第三層第一本: update( dp[i][j][w], dp[i - 1][j][0] + h )
放在第二層後面: update( dp[i][j][k], dp[i - 1][j - w][k] )
放在第三層後面: update( dp[i][j][k], dp[i - 1][j][k - w] )
然後類似01揹包。。。。把第一維拆掉倒序枚舉j。。。。。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int read()
{
int sign = 1, n = 0; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') sign = -1; c = getchar(); }
while (c >= '0' && c <= '9') { n = n*10 + c-'0'; c = getchar(); }
return n * sign;
}
typedef pair<int, int> book;
const int inf = 0x3f3f3f3f;
int N, sum, dp[2105][2105];
book b[75];
inline bool cmp(book a, book b) { return a.first > b.first; }
inline void update(int &a, int b, int c = inf) { a = min(a, min(b, c)); }
int main()
{
for (int T = read(); T--; ) {
N = read(); sum = 0;
for (int i = 1; i <= N; ++i) {
int hi = read(), wi = read();
b[i] = book(hi, wi); sum += wi;
}
sort(b + 1, b + N + 1, cmp);
memset(dp, 0x3f, sizeof(dp)); dp[0][0] = 0;
for (int i = 2; i <= N; ++i) {
for (int j = sum; ~j; --j) {
for (int k = sum; ~k; --k) {
int temp1 = inf; int temp2 = inf;
if (j >= b[i].second) temp1 = (j == b[i].second) ? dp[0][k] + b[i].first : dp[j - b[i].second][k];
if (k >= b[i].second) temp2 = (k == b[i].second) ? dp[j][0] + b[i].first : dp[j][k - b[i].second];
update(dp[j][k], temp1, temp2);
}
}
}
int res = inf;
for (int j = 1; j <= sum; ++j) {
for (int k = 1; k <= sum; ++k) {
if (dp[j][k] >= inf) continue;
int w = max(max(j, k), sum - j - k);
int h = dp[j][k] + b[1].first;
update(res, w * h);
}
}
printf("%d\n", res);
}
return 0;
}