题意:
给出n个石头的重量和得分,有一个为m的背包,问在m个背包里能装的最大得分是多少,并要求输出装入的石子编号..
如果有多个解则输出字典序最小的..
思路:
这个在背包九讲后面有提及..
主要是用一个二维数组path[i][j]表示当体积为j的时候第i件物品是否有被装入..
最后用一次循环根据if(path[i][tv]) {
ans[cnt++] = i;
tv -= v[i];
}
就可以求出路径并保存在ans里面了..
Tips:
注意找的时候应该是从i = n往前遍历..
而输出的时候应该是cnt~0
做这道题的过程中遇到一个问题就是:如果我是用二维数组来求01背包,那代码应该是
1 #include <stdio.h>
2 #include <cstring>
3 #include <algorithm>
4 using namespace std; 5
6 int v[110], w[110]; 7 int dp[101][1010], path[100010], ans[110]; 8 int main() 9 { 10 freopen("in.in", "r", stdin); 11 int T, n, m; 12 int cnt, sum; 13 scanf("%d", &T); 14 while(T--) { 15 scanf("%d %d", &n, &m); 16 memset(dp, 0, sizeof(dp)); 17 memset(path, 0, sizeof(path)); 18 cnt = 0; 19 int res = 0; 20 for(int i = 1; i <= n; ++i) 21 scanf("%d %d", &v[i], &w[i]); 22 for(int i = 1; i <= n; ++i) { 23 for(int j = m; j >=v[i]; --j) { 24 dp[i][j] = max(dp[i-1][j-v[i]]+w[i], dp[i-1][j]); 25 } 26 for (int j=v[i]-1;j>=0; j--)dp[i][j] = dp[i-1][j]; 27 } 28 printf("%d\n", dp[n][m]); 29 } 30 return 0; 31 }
因为i+1的体积可能比i小..
但是每次更新都是从v[i]~V..
所以应该把0~v[i]都加到dp[i][0~v[i]]里..
Code:
1 #include <stdio.h> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 int v[110], w[110], dp[100010], ans[110]; 7 bool path[110][10010]; 8 int main() 9 { 10 // freopen("in.txt", "r", stdin); 11 int T, n, m; 12 int cnt, sum; 13 scanf("%d", &T); 14 while(T--) { 15 scanf("%d %d", &n, &m); 16 memset(dp, 0, sizeof(dp)); 17 memset(path, 0, sizeof(path)); 18 cnt = 0; 19 for(int i = 1; i <= n; ++i) 20 scanf("%d %d", &v[i], &w[i]); 21 22 for(int i = 1; i <= n; ++i) { 23 for(int j = m; j >= v[i]; --j) { 24 int t = dp[j]; 25 dp[j] = max(dp[j-v[i]]+w[i], dp[j]); 26 path[i][j] = dp[j] == t?false:true; 27 } 28 } 29 int tv = m; 30 for(int i = n; i > 0; --i) 31 if(path[i][tv]) { 32 ans[cnt++] = i; 33 tv -= v[i]; 34 } 35 36 printf("%d\n", dp[m]); 37 for(int i = cnt-1; i >= 0; --i) 38 printf("%d%c", ans[i], i == 0?'\n':' '); 39 } 40 return 0; 41 }
链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1740