题目:click
题意:每次都有两辆车子运货,但每辆车子都有一个运货重量的上限,问最少多少次把所有货运完。
n的范围很小,可以考虑状态压缩,一开始并没有想到分两辆车不同的情况而是压缩在一块去对dp,发现复杂度会爆炸,可以先考虑一辆车一次能运多少物资,把可能的状态写出来与另外一辆的所有可能状态组合,得到的状态都是正好只能使用一次,贴合01背包。
dp[i]:达到状态i 最小需要的次数。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
const int NUM=1030;
int a[20];
int dp1[1030],dp2[1030];//枚举C1,C2一次能运的状态
int dp[1030];
int sss[1030];
int main()
{
int T;
scanf("%d",&T);
int yy=1;
while(T--)
{
memset(dp,inf,sizeof(dp));
memset(dp1,-1,sizeof(dp1));
memset(dp2,-1,sizeof(dp2));
memset(sss,-1,sizeof(sss));
int n,i,j,c1,c2,k;
scanf("%d %d %d",&n,&c1,&c2);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
dp1[0]=dp2[0]=1;
for(i=1;i<(1<<n);i++)
{
int temp=i;
int sum=0;
int cnt=0;
while(temp)
{
cnt++;
if(temp&1)
{
sum+=a[cnt];
}
temp>>=1;
}
if(sum<=c1)
{
dp1[i]=1;
}
}
for(i=1;i<(1<<n);i++)
{
int temp=i;
int sum=0;
int cnt=0;
while(temp)
{
cnt++;
if(temp&1)
{
sum+=a[cnt];
}
temp>>=1;
}
if(sum<=c2)
{
dp2[i]=1;
}
}
dp[0]=0;
for(i=0;i<(1<<n);i++)
{
for(j=0;j<=(1<<n);j++)
{
if((i&j)==0&&dp1[i]!=-1&&dp2[j]!=-1)
{
sss[i|j]=1;
}
}
}
for(i=0;i<(1<<n);i++)
{
for(j=(1<<n)-1;j>=0;j--)
{
if(sss[i]==-1)
continue;
if((j&i)==0)
dp[i|j]=min(dp[i|j],dp[j]+1);
}
}
printf("Scenario #%d:\n%d\n\n",yy++,min(dp[(1<<n)-1],n));
}
return 0;
}