题意
有n个物品体积为wi,两辆车容量分别为c1,c2,求最少要运几次;
思路
可以将一次两辆车装的物品总数当作单个状态,这样就转化为了,不重不漏取所有物品需要几步的状压dp;
枚举所有状态state(0<=state<=(1<<n)),我们可以根据每个state中1的位置求的这个状态求得当前状态物品总体积,再判断可以保存当前状态的车;
之后枚举两辆车所有装载状态进行组合,求的两车一起运输的所有状态;
转移方程
dp[j|i]=min(dp[j|i],dp[j]+1);
j是当前以取物品状态,i是当前车的装载状态,j|i是下次车的装载状态;
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10,M=1<<10;
const int INF=1e9;
int n,c1,c2,cnt1,cnt2;
int w[N];
int state1[M];
int state2[M];
int state[M];
int dp[M];
int main()
{
int T;
scanf("%d",&T);
for(int cas=1; cas<=T; cas++)
{
fill(dp,dp+M,INF);
fill(state,state+M,0);
scanf("%d%d%d",&n,&c1,&c2);
for(int i=0; i<n; i++)
scanf("%d",&w[i]);
//预处理两辆车各自装载方案
cnt1=cnt2=0;
for(int i=0; i<(1<<n); i++)
{
int sum=0;
for(int j=0; j<n; j++)
if((i>>j)&1)
sum+=w[j];
if(sum<=c1)state1[cnt1++]=i;
if(sum<=c2)state2[cnt2++]=i;
}
//合并两辆车的装载方案,因为组合起来会有重复,所以这里不离散化
for(int i=0; i<cnt1; i++)
for(int j=0; j<cnt2; j++)
state[state1[i]|state2[j]]=1;
dp[0]=0;//起点
for(int i=0; i<(1<<n); i++)
if(state[i])//代表i状态可以装载
for(int j=0; j<(1<<n); j++)
if(((j&i)==0)&&dp[j]!=INF)//起点要被更新过
dp[j|i]=min(dp[j|i],dp[j]+1);
printf("Scenario #%d:\n%d\n\n",cas,dp[(1<<n)-1]);
}
return 0;
}