ZOJ-4019 18th浙江省赛F.Schrödinger's Knapsack(dp)

题意:

给两个序列s1,s2,每个序列都有一个系数k1,k2,现在有一个总容量c,要求从这两个序列中取数,使得最后的价值最大。每个数放进背包之后获得的价值为(当前容量-这个数占的容量)*当前序列的系数。 

思路:

已知总数n和m较小,易知每个序列放入背包的顺序应该是从小到大的,所以dp[i][j]表示将s1序列的第1...i数和s2序列的第1...j数放入背包时取得的最大价值。s[i][j]表示将s1序列的第1...i数和s2序列的第1...j数放入背包时所占的容量。

则dp[i][j] = max(dp[i-1][j] + (c - s[i][j])*k1 + dp[i][j-1] + (c - s[i][j])*k2);

通过memset初始化会TLE。

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2005;
ll dp[maxn][maxn];
ll s[maxn][maxn];
ll s1[maxn], s2[maxn];
int T, k1, k2, c, n, m;
int main() {
    for(scanf("%d", &T); T--;) {
		scanf("%d %d %d", &k1, &k2, &c);
		scanf("%d %d", &n, &m);
		for(int i = 1; i <= n; ++i) {
			scanf("%lld", &s1[i]);
		}
		for(int i = 1; i <= m; ++i) {
			scanf("%lld", &s2[i]);
		}
		sort(s1+1, s1+n+1);
		sort(s2+1, s2+m+1);
//		memset(dp, 0, sizeof dp);
		for(int i = 0; i <= n+1; ++i) {
			for(int j = 0; j <= m+1; ++j) {
				dp[i][j] = 0;
				s[i][j] = 0;
			}
		}
		s[1][1] = c;
		for(int i = 1; i <= n+1; ++i) {
			if(i != 1) {
				s[i][1] = s[i-1][1] - s1[i-1];
				if(s[i][1] <= 0) break;
			}
			for(int j = 2; j <= m+1; ++j) {
				s[i][j] = s[i][j-1] - s2[j-1];
				if(s[i][j] <= 0) break;
			}
			s[i][m+1] = s[i][m] - s2[m];
		}
		ll ans = 0;
		for(int i = 1; i <= n+1; ++i) {
			for(int j = 1; j <= m+1; ++j) {
				if(s[i][j] <= 0) break;
				if(i > 1) {
					dp[i][j] = max(dp[i][j], dp[i-1][j] + s[i][j]*k1);
				}
				if(j > 1) {
					dp[i][j] = max(dp[i][j], dp[i][j-1] + s[i][j]*k2);
				}
				ans = max(ans, dp[i][j]);
			}
		}
		printf("%lld\n", ans);
    }
    return 0;
}

/*

dp[i][j] = max(dp[i-1][j] + s[i][j]*k1, dp[i][j-1] + s[i][j]*k2)

*/


继续加油~

猜你喜欢

转载自blog.csdn.net/yo_bc/article/details/80150103