ZOJ_3613
这个题目由于要求一个资源只能供给一个工厂,实际上隐含要求每个连通块里面工厂数大于或等于资源数,否则就会有部分资源是无用的,就会增加没必要的代价。这样如果在最后dp的时候加入这个隐含条件,就可以用统计连通块内的资源数来代替统计可以工作的工厂数。
另外推荐一个感觉讲这类问题讲得比较好的一个博客:http://endlesscount.blog.163.com/blog/static/821197872012525113427573/。
#include<stdio.h> #include<string.h> #define MAXD 210 #define MAXM 10010 #define ST 266 #define MAXQ 2000010 #define INF 0x3f3f3f3f const int Q = 2000000; int N, M, nn, fn, sn, first[MAXD], e, next[MAXM], v[MAXM], w[MAXM]; int bit[MAXD], q[MAXQ], inq[MAXD][ST], front, rear; int f[MAXD][ST], dp[ST]; int sum[10]; struct Planet { int a, b; }p[MAXD]; void add(int x, int y, int z) { v[e] = y, w[e] = z; next[e] = first[x], first[x] = e ++; } void init() { int i, j, k, x, y, z; fn = sn = 0; for(i = 1; i <= N; i ++) scanf("%d%d", &p[i].a, &p[i].b), fn += p[i].a > 0, sn += p[i].b; nn = 1 << fn + sn; memset(bit, 0, sizeof(bit)); for(i = 1, k = 0; i <= N; i ++) if(p[i].a) sum[k] = p[i].a, bit[i] |= 1 << (k ++); for(i = 1; i <= N; i ++) if(p[i].b) bit[i] |= 1 << (k ++); memset(f, 0x3f, sizeof(f)); for(i = 1; i <= N; i ++) if(bit[i]) f[i][bit[i]] = 0; memset(first, -1, sizeof(first)); e = 0; scanf("%d", &M); for(i = 0; i < M; i ++) { scanf("%d%d%d", &x, &y, &z); add(x, y, z), add(y, x, z); } } inline int Min(int x, int y) { return x < y ? x : y; } void spfa() { int i, x, st, y, nst; while(front != rear) { x = q[front] & 255, st = q[front] >> 8, inq[x][st] = 0; ++ front > Q ? front = 0 : 0; for(i = first[x]; i != -1; i = next[i]) { y = v[i], nst = st | bit[y]; if(f[x][st] + w[i] < f[y][nst]) { f[y][nst] = f[x][st] + w[i]; if(nst == st && !inq[y][nst]) { q[rear ++] = nst << 8 | y, inq[y][nst] = 1; rear > Q ? rear = 0 : 0; } } } } } bool check(int st) { int i, n = 0; for(i = 0; i < fn; i ++) if(st & 1 << i) n += sum[i]; for(; i < fn + sn; i ++) if(st & 1 << i) -- n; return n >= 0; } void update(int st, int c, int &num, int &cost) { int i, n = 0; for(i = 0; i < sn; i ++) if(st & 1 << i + fn) ++ n; if(n > num || (n == num && c < cost)) num = n, cost = c; } void solve() { int i, j, k, num, cost; front = rear = 0; for(i = 0; i < nn; i ++) { for(j = 1; j <= N; j ++) { for(k = i - 1 & i; k; k = k - 1 & i) f[j][i] = Min(f[j][i], f[j][k | bit[j]] + f[j][i - k | bit[j]]); if(f[j][i] < INF) q[rear ++] = i << 8 | j, inq[j][i] = 1; rear > Q ? rear = 0 : 0; } spfa(); } for(i = 0; i < nn; i ++) { dp[i] = INF; for(j = 1; j <= N; j ++) dp[i] = Min(dp[i], f[j][i]); } num = 0, cost = 0; for(i = 0; i < nn; i ++) if(check(i)) { for(j = i - 1 & i; j; j = j - 1 & i) if(check(j) && check(i - j)) dp[i] = Min(dp[i], dp[j] + dp[i - j]); if(dp[i] < INF) update(i, dp[i], num, cost); } printf("%d %d\n", num, cost); } int main() { while(scanf("%d", &N) == 1) { init(); solve(); } return 0; }