Vijos 1071 【DP之记录路径】
2013-03-16 21:08
387 查看
题意:
给出n张牌的重量和现在剩下的牌的重量。
求缺失了的牌。
如果无解就输出0 多解就输出-1 否则就按照输入的顺序输出排的编号
思路:
01背包..
状态转移用dp[v] = cnt;表示牌的总和为v的情况是为cnt
记录路径有path[v] = j; 表示是加上了第j个物品才得到体积为v的。
一开始有一个已知的是dp[0] = 1;
状态转移方程为 if(dp[j-w[i]]) dp[j] += dp[j-w[i]]; 表示当前一个状态存在的情况下,这一个状态的情况数为前一个状态加上当前这个状态的情况数。
因为题目要求给出缺失的牌的编号,所以如果dp[j] == 0,即第一次遇到这个情况,就记录当前路径。主要是因为这个是空间优化的dp,用这个来标记的原因和01背包中第二层for循环从v循环到w[i]的理由一样,都是为了防止被后面的体积影响结果。
例如 第1 2 3个物体的体积是1 2 3, 而总的体积要求是6
因为1+2+3 = 6,所以路径理论上应该是1 2 3。但是当 j 为3,i 为 3即w[i] = 3的时候dp[j-w[i]] == 1
理论上这时候path[3] 应该 = 2; 即第一个物品的体积1加上第二个物品的体积2 = 3
但是因为正好有一件物品的体积为3,所以没有 if(dp[j] == 0) path[cnt++] = i;
这时候i = 3就会覆盖掉path[3]
但实际上最后path[6] 才应该是 = 3
最后如果dp[v] = 0代表无解 dp[v] > 1代表多解 ///其中v表示缺少的牌的总重量
如果dp[v] = 1; 则按path[j-path[j-path[...]]]找出路径,最后的最后就直接把路径输出。
Tips:
题目没有说明给出的数据关系,所以可以预处理的情况是如果现在有的牌的总重量为0,则所有牌都缺失了,这时候就把输入的牌全部输出,如果缺失的牌的体积比所有牌的体积和大,那肯定是无解的。
另外有一个要注意的地方是:要先处理现在有的牌的总重量为0的情况,因为dp的时候dp[0] 被初始化为1了,如果不先处理这种特殊情况,就会输出错误的答案。
Code:
View Code
题目链接:https://vijos.org/p/1071
给出n张牌的重量和现在剩下的牌的重量。
求缺失了的牌。
如果无解就输出0 多解就输出-1 否则就按照输入的顺序输出排的编号
思路:
01背包..
状态转移用dp[v] = cnt;表示牌的总和为v的情况是为cnt
记录路径有path[v] = j; 表示是加上了第j个物品才得到体积为v的。
一开始有一个已知的是dp[0] = 1;
状态转移方程为 if(dp[j-w[i]]) dp[j] += dp[j-w[i]]; 表示当前一个状态存在的情况下,这一个状态的情况数为前一个状态加上当前这个状态的情况数。
因为题目要求给出缺失的牌的编号,所以如果dp[j] == 0,即第一次遇到这个情况,就记录当前路径。主要是因为这个是空间优化的dp,用这个来标记的原因和01背包中第二层for循环从v循环到w[i]的理由一样,都是为了防止被后面的体积影响结果。
例如 第1 2 3个物体的体积是1 2 3, 而总的体积要求是6
因为1+2+3 = 6,所以路径理论上应该是1 2 3。但是当 j 为3,i 为 3即w[i] = 3的时候dp[j-w[i]] == 1
理论上这时候path[3] 应该 = 2; 即第一个物品的体积1加上第二个物品的体积2 = 3
但是因为正好有一件物品的体积为3,所以没有 if(dp[j] == 0) path[cnt++] = i;
这时候i = 3就会覆盖掉path[3]
但实际上最后path[6] 才应该是 = 3
最后如果dp[v] = 0代表无解 dp[v] > 1代表多解 ///其中v表示缺少的牌的总重量
如果dp[v] = 1; 则按path[j-path[j-path[...]]]找出路径,最后的最后就直接把路径输出。
Tips:
题目没有说明给出的数据关系,所以可以预处理的情况是如果现在有的牌的总重量为0,则所有牌都缺失了,这时候就把输入的牌全部输出,如果缺失的牌的体积比所有牌的体积和大,那肯定是无解的。
另外有一个要注意的地方是:要先处理现在有的牌的总重量为0的情况,因为dp的时候dp[0] 被初始化为1了,如果不先处理这种特殊情况,就会输出错误的答案。
Code:
View Code
#include <stdio.h> #include <cstring> #include <ctime> #include <stdlib.h> int main() { int n, v, cnt, tv, sum; int w[110], dp[100010], path[100010], ans[110], vis[110]; while(EOF != scanf("%d", &v)) { memset(dp, 0, sizeof(dp)); memset(vis, 0, sizeof(vis)); memset(path, 0, sizeof(path)); sum = cnt = 0; scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%d", &w[i]); sum += w[i]; } if(sum <= v) puts("0"); else if(v == 0) { for(int i = 1; i <= n; ++i) printf("%d%c", i, i == n?'\n':' '); } else { v = sum-v; dp[0] = 1; for(int i = 1; i <= n; ++i) { for(int j = v; j >= w[i]; --j) { if(dp[j-w[i]] != 0) { if(dp[j] == 0) path[j] = i; dp[j] += dp[j-w[i]]; } } } if(dp[v] == 0) puts("0"); else if(dp[v] > 1) puts("-1"); else { tv = v; for(int i = path[tv]; tv > 0; i = path[tv]) { ans[cnt++] = i; tv -= w[i]; } for(int i = cnt-1; i >= 0; --i) printf("%d%c", ans[i], i == 0?'\n':' '); } } } return 0; }
题目链接:https://vijos.org/p/1071
相关文章推荐
- poj 1141 Brackets Sequence 【区间DP+路径记录】
- hdu 1160 dp (二维最长上升子序列 记录路径
- poj 2250 Compromise (DP-LCS 记录路径)
- hdu1160 FatMouse's Speed (dp,记录路径)
- ZOJ3541与时间相关的区间dp+记录路径
- hdu1074 状态压缩dp 记录路径
- hdu 1160 dp (二维最长上升子序列 记录路径
- bzoj4200 [Noi2015]小园丁与老司机(dp+记录路径+有源汇有上下界最小流)
- 最大连续子段和+记录路径 【DP 初步】
- hdu 5092 Seam Carving dp+记录路径
- POJ2264---Advanced Fruits(dp,LCS变着花样记录路径,POJ2250的升级版)
- poj 1141 Brackets Sequence(区间DP记录路径)
- Codeforces 454D Little Pony and Harmony Chest【思维+状压Dp+记录路径】好题!
- poj3003&2397 DP 记录路径
- 【DP】UVA 624 CD 记录路径
- hdu 1160 dp (二维最长上升子序列 记录路径
- poj1141 Brackets Sequence(区间dp记录路径问题)
- HDU 1224 Free DIY Tour(简单dp?+记录路径)
- Codeforces 507E Breaking Good【最短路SPFA+Dp+记录路径】好题~~~
- POJ 1141 Brackets Sequence(区间DP记录路径)