Relocation POJ - 2923(01背包+状压dp)

Relocation

链接:  POJ - 2923 
题目大意: 给你两辆车,每辆车有额定载重c1,c2,再给你n件物品(n<=10)的重量wi,每次都用两辆车往返运输,求最小的次数.
思路:看到n的数量很小,先想到暴力,可以枚举每次装车的情况,判断是否成立.先对装车的情况进行状态压缩,0代表不装,1为装,对状态进行暴力枚举.然后很容易想到用01背包进行判断方案是否可行,判断过程如下:先计算所选物品重量的总和,然后以c1车的容量进行01背包求能装下的最大重量,若 c2车的重量>总重量-c1车能装的最大重量则返回true代表可行.接着对物品的状态进行dp,将状态0转移到状态(1<<n)-1,每次转移枚举可行的装车方案,状态转移方程如下:
dp[i|sta[j]]=min(dp[i|sta[j]],dp[i]+1);

sta[j]为枚举的装车方案,i|sta[j]为装车后的装状态.

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include<iostream>
 5 #include<cmath>
 6 #define INF 0x3f3f3f3f
 7 #define MAXN 100000
 8 using namespace std;
 9 typedef long long ll;
10 int f[105],dp[1<<12],w[MAXN],sta[MAXN],c1,c2,n;
11 bool check(int st)
12 {
13     memset(f,0,sizeof(f));
14     int sum=0;
15     for(int i=0;i<n;i++)
16     {
17         if(st&(1<<i))
18         {
19             sum+=w[i];
20             if(sum>c1+c2)continue;
21             for(int j=c1;j>=w[i];j--)
22             f[j]=max(f[j],f[j-w[i]]+w[i]);
23         }
24     }
25     if(c2>=sum-f[c1])return true;
26     return false;
27 }
28 int main()
29 {
30     ios::sync_with_stdio(false);
31     int cas;
32     cin>>cas;
33     for(int ca=1; ca<=cas; ca++)
34     {
35         memset(dp,INF,sizeof(dp));
36         dp[0]=0;
37         cin>>n>>c1>>c2;
38         c1 > c2 ? c1 ^= (c2 ^= (c1 ^= c2)) : 0;
39         for(int i=0;i<n;i++)
40             cin>>w[i];
41         int cnt=0;
42         for(int i=0;i<(1<<n);i++)
43             if(check(i))sta[cnt++]=i;
44         for(int i=0;i<(1<<n);i++)
45         {
46             for(int j=0;j<cnt;j++)
47             dp[i|sta[j]]=min(dp[i|sta[j]],dp[i]+1);
48         }
49         cout<<"Scenario #"<<ca<<":"<<endl;
50         cout<<dp[(1<<n)-1]<<endl;
51         if(ca<cas)cout<<endl;
52     }
53     return 0;
54 }
View Code
 

猜你喜欢

转载自www.cnblogs.com/megadeth/p/11361007.html