#简介:
两个船要装一些货物,我们想知道是否有一种方式可以将货物全部装下。
网上的代码都是以算法与程序设计为基本,但是没有做出最后一步优化:递归返回保存路径
#这里提供一种有返回值的递归,充分利用递归来减小复杂度,使复杂度尽可能达到o(2^n),而且不像其他代码一样需要一个中间数组X[n]来保存当前路径,这个算法不需要,可以节省空间
#直接上代码,具体如下
#include <iostream>
#include <string.h>
#define YES 1 //这个可以
#define NO 0 //这个不行
#define RETURNBACK 2 //这个一定是!!!
using namespace std;
class Loading
{
public:
int MaxLoading(int*,int,int,int,int*); //初始化函数
private:
int Backtrack(int); //递归函数求解
int n; //箱子总数
int* w; //箱子重量数组
int c; //船的重量
int cw; //已装重量
int* bestx; //最佳箱子装载方式
int bestw; //最佳重量
int r; //船剩余重量
};
int Loading::Backtrack(int i)
{
/*当到达最后一个节点时*/
if(i == n-1)
{
cw += w[i];
if(cw < c)
{
if(cw > bestw) //新最优解出现
{
bestx[i] = YES;
bestw = cw;
return YES;
}
}
else if(cw == c) //真最优解出现,这里不还原cw,因为直接一直返回知道结束递归
{
bestx[i] = YES;
return RETURNBACK;
}
else //没有出现
{
cw -= w[i];
if(cw > bestw) //新最优解出现
{
bestx[i] = NO;
return YES;
}
}
return NO;
}
/*初始化记录*/
int q = NO;
int p = NO;
r -= w[i];
/*当可以装下时*/
if(cw + w[i] < c)
{
cw += w[i];
q = Backtrack(i+1);
if(q >= YES) //新最优解出现
{
bestx[i] = YES;
}
if(RETURNBACK == q) //真的最优解出现,直接返回
{
return RETURNBACK;
}
cw -= w[i];
}
/*当刚好装满时*/
else if(cw + w[i] == c)
{
bestw = c;
bestx[i] = YES;
return RETURNBACK;
}
/*当不装时,减少枝叶*/
if(cw + r > bestw) //减小一定不是最优解的子树
{
p = Backtrack(i+1);
if(YES == p) //当新最优解出现
{
bestx[i] = NO;
return YES;
}
else if(RETURNBACK == p) //当真最优解出现
{
bestx[i] = NO;
return RETURNBACK;
}
}
/*返回结果*/
r += w[i]; //还原r,避免影响上一层
if(NO == q + p)
{
return NO;
}
return YES; //这个YES是当可以装下时的返回
}
int Loading::MaxLoading(int* w,int n,int c,int r,int* x)
{
/*初始化类*/
this->bestx = x; //这里是直接给地址
this->w = w;
this->r = r;
this->c = c;
this->cw = 0;
this->n = n;
this->bestw = 0;
/*计算结果*/
this->Backtrack(0); //注意我是从0开始的递归,与网上广为流传的从1开始不一样
/*返回结果*/
return this->bestw;
}
int main()
{
int c1 = 0;
int c2 = 0;
cout << "请输入两个船的载重量,一号为小箱子,二号为大箱子" << endl;
cin >> c1 >> c2;
int n = 0;
cout << "请输入个数" << endl;
cin >> n;
/*创建记录的数据结构*/
int* w = new int[n]; //每个箱子的重量
int* x = new int[n];
int r = 0;
/*记录数据*/
cout << "请输入每个箱子的重量" << endl;
for(int i = 0; i < n; i++)
{
cin >> w[i];
r += w[i];
}
/*比较大小,判断是否可以装完*/
if(r > (c1+c2))
{
cout << "想多了,拿命给你装?" << endl;
return 0;
}
else
{
/*创建计算的数据结构*/
Loading X;
int backall = 0; //记录返回值
int* x = new int[n];
memset(x,0,n*sizeof(int)); //初始化内存
/*判断结果*/
backall = X.MaxLoading(w,n,c1,r,x);
if(backall + c2 >= r)
{
cout << "可以完全装完" << endl;
cout << "一号箱装" << backall << endl;
cout << "二号箱装" << r - backall << endl;
cout << "具体如下:" << endl;
for(int i = 0; i < n; i++)
{
if(YES == x[i])
{
cout << "第" << i+1 << "个箱子装在一号船上" << endl;
}
else
{
cout << "第" << i+1 << "个箱子装在二号船上" << endl;
}
}
}
else
{
cout << "无法装下" << endl;
}
}
/*释放动态内存*/
delete[] w;
delete[] x;
return 1;
}