Description
已知n件货物的重量,先要用两个载重量分别为c1和c2的卡车装载这些货物,问最少需要装载几次
Input
第一行为一整数T表示用例组数,每组用例第一行为三个整数n,c1和c2分别表示货物数量以及两辆卡车的载重量,第二行n个整数表示这n件物品的重量
Output
对于每组用例,输出将这些货物装载完毕所需的最少装载次数,每组用例后跟一空行
Sample Input
2
6 12 13
3 9 13 3 10 11
7 1 100
1 2 33 50 50 67 98
Sample Output
Scenario #1:
2
Scenario #2:
3
Solution
枚举2^n种状态,从中找出可以一次被两辆卡车一次装完的状态并记录,将这些状态看作物品,重量为状态,价值为1,那么问题转化为01背包问题,转移方程dp[j|sta[i]]=min(dp[j|sta[i]],dp[j]+1),答案即为dp[(1<
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define INF 1<<30
int t,n,c1,c2,w[10],dp[1<<10],sta[1<<10],res;
bool check(int x)
{
bool vis[1<<10];//标记数组
int sum=0;
for(int i=1;i<=c1;i++)//初始化
vis[i]=0;
vis[0]=1;
for(int i=0;i<n;i++)
if((1<<i)&x)
{
sum+=w[i];//此种状态的所运货物的总重量
for(int j=c1-w[i];j>=0;j--)
if(vis[j])//j重量可以运那么j+w[i](<=c1)重量也可以运
vis[j+w[i]]=1;
}
for(int i=c1;i>=0;i--)//枚举c1车所运货物重量寻找合法解
if(vis[i]&&sum-i<=c2)//找到合法解
return true;
return false;//无解
}
int main()
{
scanf("%d",&t);
for(int test=1;test<=t;test++)
{
scanf("%d%d%d",&n,&c1,&c2);
if(c1>c2)swap(c1,c2);
for(int i=0;i<n;i++)
scanf("%d",&w[i]);
res=0;
for(int i=0;i<1<<n;i++)//枚举所有状态找到合法状态
if(check(i))
sta[res++]=i;
for(int i=0;i<1<<n;i++)//初始化
dp[i]=INF;
dp[0]=0;
for(int i=0;i<res;i++)//01背包
for(int j=(1<<n)-1-sta[i];j>=0;j--)
if(!(j&sta[i]))
dp[j|sta[i]]=min(dp[j|sta[i]],dp[j]+1);
printf("Scenario #%d:\n",test);
printf("%d\n\n",dp[(1<<n)-1]);
}
return 0;
}