题目描述
给定n个集装箱要装上一艘载重量为c的轮船,其中集装箱i的重量为wi。集装箱装载问题要求确定在不超过轮船载重量的前提下,将尽可能多的集装箱装上轮船。
由于集装箱问题是从n个集装箱里选择一部分集装箱,假设解向量为X(x1, x2, …, xn),其中xi∈{0, 1}, xi =1表示集装箱i装上轮船, xi =0表示集装箱i不装上轮船。
输入
每组测试数据:第1行有2个整数c和n。C是轮船的载重量(0<c<30000),n是集装箱的个数(n≤20)。第2行有n个整数w1, w2, …, wn,分别表示n个集装箱的重量。
输出
对每个测试例,输出两行:第1行是装载到轮船的最大载重量,第2行是集装箱的编号。
用回溯法解装载问题时,其解空间是一棵子集树,与0—1背包问题的解空间树相同。
代码
#include <iostream>
#include<bits/stdc++.h>
#define N 100
#define NUM 100
#define INF 0x3f3f3f3f
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(i,a,n) for(int i=a;i<=n;i++)
typedef long long ll;
using namespace std;
int n;//集装箱的数量
int c;//集装箱的载重量
int w[N];//集装箱的重量数组
int x[N];//当前搜索的解向量
int r;//剩余集装箱的重量
int cw;//当前轮船的载重量
int bestw;//当前最优载重量
int bestx[N];//当前最优解
void Backtrack(int t)//搜索t层结点
{
//到达叶子结点
if(t>n)
{
//更新最优解
if(cw>bestw)
{
for(int i=1;i<=n;i++)
{
bestx[i]=x[i];
bestw=cw;
}
}
return;
}
//更新剩余集装箱的重量
r-=w[t];
//搜索左子树
if(cw+w[t]<=c)
{
x[t]=1;//可以放进去
cw+=w[t];//加上重量
Backtrack(t+1);//下一层
cw-=w[t];
}
if(cw+r>bestw)
{
x[t]=0;
Backtrack(t+1);
}
r+=w[t];//恢复状态
}
int main()
{ cin>>c>>n;
r=0;
for(int i=1;i<=n;i++)
{
cin>>w[i];
r+=w[i];
}
Backtrack(1);
cout<<bestw<<endl;//输出最大重量
for(int i=1;i<=n;i++)
{
cout<<bestx[i]<<" ";//输出解向量
}
}