题意:给你n件货物的重量(n<=10),有两辆车,承重量分别为c1,c2,问你每次两辆车一起走,最少多少个回合能运完。
思路:货物数量很少,二进制记录状态,用背包预处理能一次运完的状态,再从初始全1状态开始bfs,到达全0状态结束。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n, c1, c2, cas=1;
int p2[12], c[12], flag[1500], vis[105], step[1505], cnt;
//flag记录能一次运走的状态
void init(){
int i, j, k, t, s;
cnt=0;
scanf("%d%d%d", &n, &c1, &c2);
if(c1>c2)swap(c1, c2);
for(i=0; i<n; i++)
scanf("%d", &c[i]);
memset(flag, 0, sizeof(flag));
for(i=0; i<p2[n]; i++){
memset(vis, 0, sizeof(vis));
vis[0]=1;s=0;
for(j=0, t=i; j<n; j++, t>>=1){
if(t&1){
s+=c[j];
for(k=c1; k>=c[j]; k--) //0/1背包处理
if(vis[k-c[j]])vis[k]=1;
}
}
for(j=c1; j>=0; j--){
if(vis[j])break;
}
if(s-j<=c2)
flag[cnt++]=i;
}
}
void solve(){
queue<int> q;
q.push(p2[n]-1);
int i, head, next;
memset(step, -1, sizeof(step));
step[p2[n]-1]=0;
while(!q.empty()){
head=q.front();
q.pop();
for(i=0; i<cnt; i++){
if(head&flag[i]==flag[i])next=head^flag[i];
else continue;
if(step[next]<0){
q.push(next);
step[next]=step[head]+1;
}
if(next==0)break;
}
if(step[0]>=0)break;
}
if(cas>1)printf("\n");
printf("Scenario #%d:\n", cas++);
printf("%d\n", step[0]);
}
int main(){
//freopen("1.txt", "r", stdin);
int i, T;
for(i=0; i<=10; i++)
p2[i]=1<<i;
scanf("%d", &T);
while(T--){
init();
solve();
}
return 0;
}