POJ 2923 Relocation 状态压缩DP + 0-1背包
比较综合的题目。
题意:有n个物品,有两辆车载重分别是c1,c2.问需要多少趟(c1,c2一起运一次就算1趟)能把物品运完。
n比较小,只有10,而且需要把所有物品全部运完,便想到状态压缩来保存状态。
首先记录好所有的可行状态,对于状态state能一趟运完。
然后再利用01背包,dp[j],表示已运的状态为j,如果状态j与state[i]不冲突,则可以从状态j运一趟变为j|state[i]。
View Code
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int n,w[11]; int dp[1026]; int state[1026]; bool vis[1026]; int num,sum, c1, c2; bool judge(int zt)//判断zt这个状态能不能由c1,c2共同运送一次就能完成。 { int i, j; memset(vis,0,sizeof(vis)); vis[0]=1;sum=0; for(i=0;i<n;i++) if(zt&(1<<i))//第i个物品属于这个状态 { sum+=w[i]; for(j=c1;j>=w[i];j--)//0-1背包 if(vis[j-w[i]])vis[j]=1; } for(i=0;i<=c1;i++) if(vis[i]&&sum-i<=c2)return 1;//判断c1,c2运送一次就能把这个状态完成。 return 0; } int main() { int cas, i, j, X=1; scanf("%d",&cas); while(cas--) { scanf("%d%d%d",&n,&c1,&c2); for(i=0;i<n;i++)//注意必须从0开始读入,不然会影响二进制运算。 scanf("%d",&w[i]); num=0; for(i=0;i<(1<<n);i++) if(judge(i))state[num++]=i; memset(dp,127,sizeof(dp));//赋值正无穷,int范围最大值 dp[0]=0; for(i=0;i<num;i++)//dp[i]表示运走二进制组合数为i的货物最少需要几趟,i表示一个状态 for(j=((1<<n)-1)-state[i];j>=0;j--) if(!(j&state[i]))//if这句话可以不写,但它的存在更能体现对dp的理解 { dp[j|state[i]]=min(dp[j|state[i]],dp[j]+1); } printf("Scenario #%d:\n%d\n\n",X++,dp[(1<<n)-1]); } return 0; }


浙公网安备 33010602011771号