POJ 2923 dp 状态压缩
2017-08-23 00:00
381 查看
dp
记忆化搜索
/* POJ 2923 解法为状态压缩DP+背包, 本题的解题思路是先枚举选择若干个时的状态, 总状态量为1<<n,判断这些状态集合里的那些物品能否一次就 运走,如果能运走,那就把这个状态看成一个物品。预处理完能 从枚举中找到tot个物品,再用这tol个物品中没有交集 (也就是两个状态不能同时含有一个物品)的物品进 行01背包,每个物品的体积是state[i],价值是1,求 包含n个物品的最少价值也就是dp[(1<<n)-1](dp[i]表示状态i需要运的最少次数)。 状态转移方程:dp[j|k] = min(dp[j|k],dp[k]+1) (k为state[i,1<=j<=(1<<n)-1])。 算法复杂度O((2^N)*N) */ #include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> #include <math.h> using namespace std; const int INF = 0x3f3f3f3f; int state[1030]; int tol; int dp[1030]; int n, C1, C2; int cost[110]; int vis[1030]; int dp2[1030]; //判断状态是否满足要求,先按照01背包,然后看剩下的第二个是不是可以装走 bool judge2(int x){ memset(dp2, 0, sizeof(dp2)); memset(vis, 0, sizeof(vis)); int cnt = 1, sum = 0; for (int i = 0; i < n; i++) if (x & (1 << i)){ vis[cnt++] = cost[i], sum += cost[i]; } if (sum > C1 + C2) return 0; for (int i = 1; i <= cnt; i++) dp2[i] = 0; for (int i = 1; i <= cnt; i++){ for (int v = C1; v >= vis[i]; v--) dp2[v] = max(dp2[v], dp2[v - vis[i]] + vis[i]); } if (dp2[C1] + C2 < sum) return 0; else return 1; } //判断x是否满足状态 bool judge(int x){ int sum = 0; memset(vis, 0, sizeof(vis)); //第一辆车可以不装 vis[0] = true; //遍历每一个位置 for (int i = 0; i < n; i++){ if ((1 << i) & x){ sum += cost[i]; //剩余空间可以装下第i个东西 for (int j = C1; j >= cost[i]; j--) if (vis[j - cost[i]]) //如果放入后的状态可行,则该状态可行 vis[j] = true; } } //如果总数太多 if (sum > C1 + C2) return false; //遍历第一辆车可以装的数目,如果第一辆车可以装这么多,并且剩下的第二辆车也能装下 for (int i = 0; i <= C1; i++) if (vis[i] && sum - i <= C2) return true; return false; } int main(){ freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); int T; int iCase = 0; scanf("%d", &T); while (T--){ iCase++; scanf("%d%d%d", &n, &C1, &C2); for (int i = 0; i < n; i++) scanf("%d", &cost[i]); for (int i = 0; i < (1 << n); i++) dp[i] = INF; dp[0] = 0; tol = 0; for (int i = 1; i < (1 << n); i++) if (judge(i)) state[tol++] = i; for (int i = 0; i < tol; i++) for (int j = (1 << n) - 1; j >= 0; j--){ if (dp[j] == INF) continue; if ((j & state[i]) == 0){ dp[j | state[i]] = min(dp[j | state[i]], dp[j] + 1); } } printf("Scenario #%d:\n%d\n\n", iCase, dp[(1 << n) - 1]); } return 0; }
记忆化搜索
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <cmath> #include <stack> #include <vector> #define LL long long #define myabs(x) ((x) > 0 ? (x) : (-(x))) using namespace std; const int inf = 0x3f3f3f3f; const int maxn = (1 << 10) + 10; int f[maxn], goods[maxn]; int damn[110]; int w[15]; int n, c1, c2, tot; int judge(int x){ int i, j; memset(damn, 0, sizeof(damn)); int sum = 0; for (i = 0; (1 << i) <= x; i++){ if (x & (1 << i)){ sum += w[i + 1]; for (j = c1; j >= w[i + 7fe0 1]; j--) damn[j] = max(damn[j], damn[j - w[i + 1]] + w[i + 1]); } } if (sum - damn[c1] <= c2) return 1; else return 0; } int dfs(int sta){ if (f[sta] != -1) return f[sta]; if (sta == 0) return 0; int i; f[sta] = inf; int tem; for (i = 0; i < tot; i++){ if (sta >= goods[i] && ((sta - goods[i]) & goods[i]) == 0){ tem = dfs(sta - goods[i]) + 1; if (tem < f[sta]) f[sta] = tem; } } return f[sta]; } int main(){ int T; cin >> T; int cas = 0; while (T--){ scanf("%d%d%d", &n, &c1, &c2); int i; tot = 0; for (i = 1; i <= n; i++) scanf("%d", &w[i]); for (i = 1; i < (1 << n); i++) if (judge(i)) goods[tot++] = i; memset(f, -1, sizeof(f)); int ans = dfs((1 << n) - 1); int j; printf("Scenario #%d:\n%d\n\n", ++cas, ans); } return 0; }
相关文章推荐
- POJ 2923 Relocation(状态压缩 + 两次DP)
- POJ 2923 Relocation / 状态压缩DP
- POJ 2923 Relocation(状态压缩DP)
- poj 2923(状态压缩dp)
- POJ 2923 Relocation(状态压缩DP+DP:01背包)
- POJ 2923 Relocation(01背包变形, 状态压缩DP)
- poj 2923 状态压缩dp
- 状态压缩DP——POJ 2923
- poj 2923 dp状态压缩+背包(两辆货车来运货)
- poj 3254 Corn Fields 状态压缩dp
- poj 2411 Mondriaan's Dream(状态压缩dp)
- poj 2411 Mondriaan's Dream (状态压缩dp 入门)
- POJ 2288(状态压缩dp)
- poj Corn Fields 3254 状态压缩dp
- poj 2411 && zoj 1100 Mondriaan's Dream ———状态压缩dp
- POJ 1185 (状态压缩DP)
- poj 2411/hdu 1400 Mondriaan's Dream 状态压缩dp
- POJ-1699 Best Sequence 状态压缩DP
- POJ 2411 Mondriaan's Dream 贴砖块类状态压缩DP入门
- POJ 1185 炮兵阵地(状态压缩DP)