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 }

 

posted @ 2015-03-19 22:29  miao_a_miao  阅读(260)  评论(0编辑  收藏  举报