POJ2184Cow Exhibition (01背包变形)
思路一下子就想到了,转移方程却没想好,看到网上一个的思路相同的代码,改的转移方程。
同时dp全部初始化为负无穷,需要注意一下。
AC代码如下:
/************************************************** Memory: 1884 KB Time: 250 MS Language: G++ Result: Accepted **************************************************/ #include <iostream> #include <cstdio> #include <cstring> using namespace std; /** 题目描述: n头牛(1-n),每个牛有两个值Si和Fi,选其中任意头,使s和f的和最大,其中s和f各自和都不能为负数 */ int s[105], f[105]; int dp[200005]; int num[200005]; const int INF = 0x5f5f5f5f; int main() { int n; while (cin >> n) { int m = 0; for (int i = 0; i < n; ++i) { cin >> s[i] >> f[i]; s[i] += 1000; // 全部加上1000保证非负 m += s[i]; } for (int i = 0; i <= m; ++i) dp[i] = -INF; memset(num, 0, sizeof num); dp[0] = 0; // 保证所有dp的值都是正好装满。。 for (int i = 0; i < n; ++i) { for (int j = m; j >= s[i]; --j) { //if (dp[j] < dp[j - s[i]] + f[i]) if (dp[j] - num[j] * 1000 < dp[j - s[i]] + f[i] - (num[j - s[i]] + 1) * 1000) { // 这转移方程我也是醉了。。保证的是s和为j时s和f的和最大 dp[j] = dp[j - s[i]] + f[i]; num[j] = num[j - s[i]] + 1; // 记录用了多少头牛。。 } //printf("dp[%d]=%d, num[%d]=%d\n", j, dp[j],j, num[j]); } } int ans = 0; for (int j = 0; j <= m; ++j) { if (dp[j] >= 0 && j - num[j] * 1000 >= 0) ans = max(ans, dp[j] + j - num[j] * 1000); } cout << ans << endl; } return 0; }