poj 2923 状压dp+01背包
好牛b的思路
题意:一系列物品,用二辆车运送,求运送完所需的最小次数,两辆车必须一起走
解法为状态压缩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)
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 #include<algorithm> 5 #include<math.h> 6 using namespace std; 7 const int INF=0x3f3f3f3f; 8 int state[1030]; 9 int tol; 10 int dp[1030]; 11 int n,C1,C2; 12 int cost[110]; 13 bool vis[1030]; 14 15 bool judge(int x) 16 { 17 int sum=0; 18 memset(vis,false,sizeof(vis)); 19 vis[0]=true; 20 for(int i=0;i<n;i++) 21 { 22 if((1<<i)&x) 23 { 24 sum+=cost[i]; 25 for(int j=C1;j>=cost[i];j--) 26 if(vis[j-cost[i]]) 27 vis[j]=true; 28 } 29 } 30 if(sum>C1+C2)return false; 31 for(int i=0;i<=C1;i++) 32 if(vis[i]&&sum-i<=C2) 33 return true; 34 return false; 35 } 36 int main() 37 { 38 int T; 39 int iCase=0; 40 scanf("%d",&T); 41 while(T--) 42 { 43 iCase++; 44 scanf("%d%d%d",&n,&C1,&C2); 45 for(int i=0;i<n;i++) 46 scanf("%d",&cost[i]); 47 for(int i=0;i<(1<<n);i++)dp[i]=INF; 48 dp[0]=0; 49 tol=0; 50 for(int i=1;i<(1<<n);i++) 51 if(judge(i)) 52 state[tol++]=i; 53 for(int i=0;i<tol;i++) 54 for(int j=(1<<n)-1;j>=0;j--) 55 { 56 if(dp[j]==INF)continue; 57 if((j&state[i])==0) 58 { 59 dp[j|state[i]]=min(dp[j|state[i]],dp[j]+1); 60 } 61 } 62 printf("Scenario #%d:\n%d\n\n",iCase,dp[(1<<n)-1]); 63 } 64 return 0; 65 }