回溯法求解装载问题

问题描述

有n个集装箱要装上一艘载重量为W的轮船,其中集装箱i(1≤i≤n)的重量为wi。不考虑集装箱的体积限制,现要从这些集装箱中选出重量和小于等于W并且尽可能大的若干装上轮船。
例如,n=5,W=10,w={5,2,6,4,3}时,其最佳装载方案是(1,1,0,0,1)或者(0,0,1,1,0),maxw=10。

问题求解

采用带剪枝的回溯法求解。问题的表示如下:
int w[]={0,5,2,6,4,3}; //各集装箱重量,不用下标0的元素
int n=5,W=10;
求解的结果表示如下:
int maxw=0; //存放最优解的总重量
int x[MAXN]; //存放最优解向量
将上述数据设计为全局变量。
求解算法如下:
void dfs(int i,int tw,int rw,int op[])
其中参数i表示考虑的集装箱i,tw表示选择的集装箱重量和,rw表示剩余集装箱的重量和(初始时为全部集装箱重量和),op表示一个解,即对应一个装载方案。
最优解:x,maxw
左剪枝:仅仅扩展tw+w[i]≤W的左孩子结点
右剪枝:仅仅扩展tw+rw-w[i]>maxw的右孩子结点

代码

int w[] = { 0,5,2,6,4,3 };
int n = 5, W = 10;
int maxw = 0;
int x[MAX];//存放最优解

void dfs(int i, int tw, int rw, int op[])
{
	if (i > n)
	{
		if (tw > maxw&&tw <= W)
		{
			maxw = tw;
			for (int j = 1; j <= n; j++)
				x[j] = op[j];
		}
	}
	else
	{
		if (tw + w[i] <= W)//左剪枝
		{
			op[i] = 1;//选择货物
			dfs(i + 1, tw + w[i], rw - w[i], op);
		}
		if (tw + rw - w[i] > maxw)//右剪枝
		{
			op[i] = 0;//不选择货物
			dfs(i + 1, tw, rw - w[i], op);
		}
	}
}

求解复杂装载问题

问题描述

有一批共n个集装箱要装上两艘载重量分别为c1和c2的轮船,其中集装箱i的重量为wi,且w1+w2+…+wn≤c1+c2。
装载问题要求确定是否有一个合理的装载方案可将这些集装箱装上这两艘轮船。如果有,找出一种装载方案。
例如:
n=3,c1=c2=50,w={10,40,40}时,可以将集装箱1和2装到第一艘轮船上,而将集装箱3装到第二艘轮船上。
n=3,c1=c2=50,w={20,40,40},则无法将这3个集装箱都装上轮船。

问题求解

如果一个给定的复杂装载问题有解,则可以采用如下方式得到一个装载方案:
首先将第一艘轮船尽可能装满,然后将剩余的集装箱装在第二艘轮船上。
可以用反证法证明其正确性。
如果这样做得不到一个装载方案,说明该复杂装载问题没有解!
算法思路(输入为w1,w2,…,wn,c1,c2):
(1)将尽可能多的集装箱装到第一艘轮船上,得到解向量x。
(2)累计第一艘轮船装完后剩余的集装箱重量sum。
(3)若sum<=c2,表示第二艘轮船可以装完,返回true;否则表示第二艘轮船不能装完,返回false。

代码

int w[] = { 0,10,40,40 };
int n = 3;
int c1 = 50, c2 = 50;
int maxw = 0;//存放第一艘轮船的最优总重量
int x[MAX];//存放第一艘轮船的最优解向量

void dfs(int i, int tw, int rw, int op[])
{
	if (i > n)
	{
		if (tw > maxw&&tw <= c1)
		{
			maxw = tw;
			for (int j = 1; j <= n; j++)
				x[j] = op[j];
		}
	}
	else
	{
		if (tw + w[i] <= c1)//左剪枝
		{
			op[i] = 1;//选择货物
			dfs(i + 1, tw + w[i], rw - w[i], op);
		}
		if (tw + rw - w[i] > maxw)//右剪枝
		{
			op[i] = 0;//不选择货物
			dfs(i + 1, tw, rw - w[i], op);
		}
	}
}

bool solve()
{
	int sum = 0;
	for (int j = 1; j <= n; j++)
		if (x[j] == 0)
			sum += w[j];//计算剩余货物的总重量
	if (sum <= c2)
		return true;
	else
		return false;
}
发布了26 篇原创文章 · 获赞 0 · 访问量 293

猜你喜欢

转载自blog.csdn.net/weixin_42729072/article/details/104905407