【01揹包】Uvalive4015 Caves && Uvalive3637 The Bookcase

微笑我要相信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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章