问题:给定n个集装箱,要装上载重量为c的轮船,其中集装箱i的重量为w[i],求不超过轮船最大载重量的前提下,所能装的集装箱的最大重量。
注意:集装箱不可以分割
#include<bits/stdc++.h>
#define NUM 100
using namespace std;
int n; //集装箱的总数量
int c; //轮船的载重量
int w[NUM]; //保存每个集装箱的重量
int x[NUM]; //当前搜索的解向量
int r; //剩余集装箱的总重量
int cw; //当前轮船的总重量
int bestw; //当前最优载重量
int bestx[NUM];//当前最优解
//回溯算法
//t表示第t层结点,一般从0开始
void Backtrack(int t)
{
if(t>n)//到了叶子结点处
{
if(cw>bestw)//如果在该节点处的cw值大于之前已经存在的最优解,那么就要更新最优解的值
{
for(int i=1;i<=n;i++)
{
bestx[i]=x[i];
}
bestw=cw;
}
return ;
}
/*
若果t不是叶子结点的话,那就从t开始考虑装船的问题
包括左右子树
*/
r-=w[t];//t装上之后剩余的集装箱的总重量
//搜索左子树
if(cw+w[t]<=c)
{
x[t]=1;//表示装上了第t个集装箱
cw+=w[t];
//继续遍历左子树,在讨论下一个集装箱是否可以装上
Backtrack(t+1);
//遍历完成后,需要返回t结点,此时需要恢复t结点之前的状态
cw-=w[t];
}
//搜索右子树
/*
搜索右子树的前提是已经搜索完左子树,也就是已经产生了当前的最优解
所以在搜做右子树之前只需要先判断当前轮船的载重量加上剩余的集装箱的载重量是否小于当前的最优解
如果小于,则没有继续讨论的必要,否则,可以讨论
*/
if(cw+r>bestw)
{
x[t]=0;
Backtrack(t+1);
}
r+=w[t];//恢复现场
}
//对r初始化
void init()
{
r=0;
cout<<"输入每个集装箱的重量:"<<endl;
for(int i=1;i<=n;i++)
{
cin>>w[i];
r+=w[i];
}
}
int main()
{
cout<<"第一行:轮船的最大载重量、集装箱的个数:"<<endl;
cin>>c>>n;
init();
Backtrack(0);
cout<<bestw;
cout<<endl;
for(int i=1;i<=n;i++)
{
if(bestx[i]==1)
{
cout<<i<<" ";
}
}
return 0;
}