POJ2923--Relocation(01背包+状压dp)
果然对状压DP,我根本就不懂=。=
/************************************************** Problem: 2923 User: G_lory Memory: 720K Time: 157MS Language: G++ Result: Accepted **************************************************/ #include <iostream> #include <cstring> #include <cstdio> using namespace std; const int MAXN = 1 << 11; const int INF = 0x5f5f5f5f; int n, c1, c2; int w[12]; int dp[MAXN]; int vis[MAXN]; int bag[MAXN]; bool ok(int st) { memset(vis, 0, sizeof vis); vis[0] = 1; int sum = 0; for (int i = 0; i < n; ++i) { if ((1 << i) & st)//if (i & n) { sum += w[i]; if (sum > c1 + c2) return false;// 很好理解,如果比两个车装的物体和还大,不可能一次装完 for (int j = c1; j >= w[i]; --j) { if (vis[j - w[i]]) // 对n这个状态含有的物体做01背包, vis[j] = 1; // vis[j]=1表示物体可以刚好组成j,且j可以c1被装下 } } } for (int i = 0; i <= c1; ++i) // 就是看sum能否被两车一次装下 if (sum - i <= c2 && vis[i]) return true; return false; } int main() { int t; scanf("%d", &t); for (int cas = 1; cas <= t; ++cas) { scanf("%d%d%d", &n, &c1, &c2); for (int i = 0; i < n; ++i) { scanf("%d", &w[i]); } int st = (1 << n) - 1; int cnt = 0; for (int i = 1; i <= st; ++i) { if (ok(i)) { bag[cnt++] = i; } } for (int i = 1; i <= st; ++i) dp[i] = INF; dp[0] = 0; for (int i = 0; i < cnt; ++i) { for (int j = st; j >= 0; --j) { if (dp[j] != INF && (j & bag[i]) == 0) { dp[j | bag[i]] = min(dp[j | bag[i]], dp[j] + 1); } } } printf("Scenario #%d:\n%d\n\n", cas, dp[st]); } return 0; }