POJ 2923 Relocation【状态压缩DP+01背包】
题意: 有 n 个货物,并且知道了每个货物的重量,每次用载重量分别为c1,c2的火车装载,问最少需要运送多少次可以将货物运完。
分析: 找出所有状态(1.....(1<<n)-1)中选出可以用两辆车一次运完的状态
把每个状态都看作一个物品,重量为该状态的总重量,价值为 1
求解 01 背包,dp[(1<<n)-1]为最优解
转移方程: dp[stat|j]=min(dp[stat|j],dp[j]+1) 注意 stat 和 j 不能有交集
#include<stdio.h> #include<string.h> #define clr(x)memset(x,0,sizeof(x)) #define min(a,b)(a)<(b)?(a):(b) #define INF 0x1f1f1f1f int dp[1<<11]; int a[1<<11]; int v[1<<11]; int w[111]; int st,top,n; int c1,c2; int ok(int stat) { int s=0; clr(v); v[0]=1; int i,j; for(i=0;i<n;i++) if((1<<i)&stat) { s+=w[i]; if(s>c1+c2) return 0; for(j=c1;j>=w[i];j--) if(v[j-w[i]]) v[j]=1; } for(i=0;i<=c1;i++) if(s-i<=c2&&v[i]) return 1; return 0; } int main() { int t,i,j,ca=1; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&c1,&c2); for(i=0;i<n;i++) scanf("%d",&w[i]); memset(dp,INF,sizeof(dp)); dp[0]=0; st=(1<<n)-1; top=0; for(i=1;i<=st;i++) if(ok(i)) a[top++]=i; for(i=0;i<top;i++) for(j=st;j>=0;j--) if(dp[j]!=INF) { if(j&a[i]) // 两个状态不能有交集 continue; dp[a[i]|j]=min(dp[a[i]|j],dp[j]+1); } printf("Scenario #%d:\n%d\n\n",ca++,dp[st]); } return 0; }