問題:給定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;
}