问题描述:有一批共n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i的重量是wi,且不能超过轮船总载重量。即Σwi<=c1+c2。若集装箱能全部装载则输出YES, 否则输出为NO,n为0时结束输入。
问题模型:解子集空间树。
解决思路:首先将第一艘轮船尽可能的装满。然后将剩余的集装箱装上第二艘轮船。将第一艘轮船尽可能的装满等价于选取全体集装箱的一个子集,使该子集中集装箱重量之和最接近c1。第一艘船装载完后,根据剩余的集装箱重量与c2轮船载重量比较。若剩余的集装箱重量<=c2则能装入到两艘船。(求出不超过c1的最大值max,若集装箱总重量-max<=c2则能装入到两艘船)
c1最大装载代码:
void backpack(int t){ if(t>n){ if(cw>bestw){ bestw = cw; } }else{ for(int j = 0;j<=1;j++){ //枚举物体t所有可能的路径, x[t] = j; if(cw+w[t]*x[t]<=c1){ //约束为当前集装箱的重量不能超过c1剩余重量 cw+=w[t]*x[t]; backpack(t+1); cw-=w[t]*x[t]; } } } }完整代码:
/** @回溯-装载问题 @求出不超过c1的最大值max,若物体总重量-max<=c2则能装入到两艘船。 */ #include<iostream> #include<algorithm> #define MAX 100 using namespace std; int n; //物品个数 int c1,c2; //轮船载重 int w[MAX]; //物品重量 int x[MAX]; //物品选择 int cw = 0; //当前装载量 int bestw = 0; //最优装载 void backpack(int t){ if(t>n){ if(cw>bestw){ bestw = cw; } }else{ for(int j = 0;j<=1;j++){ //枚举物体t所有可能的路径, x[t] = j; if(cw+w[t]*x[t]<=c1){ //约束为当前集装箱的重量不能超过c1剩余重量 cw+=w[t]*x[t]; backpack(t+1); cw-=w[t]*x[t]; } } } } int main(){ cin>>c1>>c2>>n; //轮船c1,c2最大载重量以及集装箱数量 while(n){ int k = 1; int sum = 0; //集装箱总重量 for(int i = 1;i<=n;i++){ cin>>w[k]; sum+=w[k]; k++; } backpack(1); if(sum-bestw<=c2){ //集装箱剩余重量与c2轮船载重量比较 cout<<"YES"<<endl; }else{ cout<<"NO"<<endl; } bestw = 0; //bestw复位0 cin>>c1>>c2>>n; } return 0; } /** 7 8 2 8 7 7 8 2 8 8 7 8 3 3 3 8 0 0 0 */