旅行售货员问题的回溯法求解

旅行售货员问题的解空间是一颗排序树,对于排序树的回溯法搜索与生成1,2,3,4,…,n的所有排列的递归算法Perm类似,开始时,x = [1,2,…,n],则相应的排序树由x[1:n]的所有排序构成。以下解释排序算法Perm:

(1)假设Perm(1)的含义是对x = [1,2,…,n]进行排序,则Perm(i)的含义是对[i,i+1,i+2,…,n]进行排序。为了方便描述,规定一个操作P(j),表示在数组x中,第j个与第一个交换,于是得到递归关系式:     Perm(i) = P(i)Perm(i+1) + P(i+1)Perm(i+1) + …+P(n)Perm(i+1)

(2)旅行售货员的回溯法Backtrack在Perm的基础上使用了剪枝函数,将无效的全排列和有效的全排列非最优的次序统统都舍去。

以下为源代码:

#include "stdafx.h"
<pre name="code" class="cpp">#include <iostream>
using namespace std;
#define N 4
#define NoEdge -1  //无边标记-1

class Traveling
{
	friend double TSP(double (*a)[N+1], int n);
private:
	void Backtrack(int i);
	void Swap(int &x, int &y);
	int n; //图G的顶点数
	int *x; //当前解
	int *bestx; //最优解,保存全排列中最优的解
	double (*a)[N+1]; //图G的邻接矩阵
	double cc; //当前费用
	double bestc; //当前最优值	
	bool iscycle; //判断是否有回路
};


void Traveling::Backtrack(int i) //对数组x中第i起到结尾进行全排列的试探,数组x下标为0的元素保留不用
{
	if(i == n) //找到符合条件的全排列
	{
		if (a[x[i-1]][x[i]] != NoEdge && a[x[i]][x[1]] != NoEdge && (bestc > cc + a[x[i-1]][x[i]] +a[x[i]][x[1]] || bestc == NoEdge)) //判断是否有回路、发现最优值
		{
			iscycle = true;
			bestc = cc + a[x[i-1]][x[i]] +a[x[i]][x[1]]; //保存最优值
			for (int i = 1; i <= n; i++)
			{
				bestx[i] = x[i]; //保存最优解
			}			
		}
	}
	else
	{
		for (int j =i; j <= n; j++)
		{
			if(a[x[i-1]][x[j]] != NoEdge && (cc + a[x[i-1]][x[j]] < bestc || bestc == NoEdge))
			{
				Swap(x[i],x[j]);
				cc += a[x[i-1]][x[i]];
				Backtrack(i+1);
				cc -= a[x[i-1]][x[i]];
				Swap(x[i],x[j]);
			}
		}
	}
}

void Traveling::Swap(int &x, int &y)
{
	int temp;
	temp = x;
	x = y;
	y= temp;
}

double TSP(double (*a)[N+1], int n)
{
	Traveling T;
	//初始化T
	T.bestc = NoEdge;
	T.cc = 0;
	T.n = n;
	T.x = new int[n+1];
	T.bestx = new int[n+1];
	T.a = a;
	T.iscycle = false;
	//置x为单位排列
	for (int i = 1; i <= n; i++)
	{
		T.x[i] = i;
	}
	T.Backtrack(2); //以T.x数组中下标为1的顶点作为旅行售货员的出发点。
	if (T.iscycle)
	{
		cout<<"旅行售货员的最优回路代价:"<<T.bestc<<endl<<"旅行售货员的最优回路路径:";
		for (int i = 1; i <= n; i++)
		{
			cout<<T.bestx[i]<<" ";
		}
		cout<<1<<endl;
	}	
	else
		cout<<"图中无回路"<<endl;
	system("pause");
	delete [] T.x;
	delete [] T.bestx;
	return T.bestc;	
}

int _tmain(int argc, _TCHAR* argv[])
{
	//对图a的初始化
	double a[N+1][N+1];
	a[1][2] = 30; //30
	a[1][3] = 6;
	a[1][4] = 4;
	a[2][3] = 5;
	a[2][4] = NoEdge; //10
	a[3][4] = 20;
	for (int i = 1; i <= N; i++)
	{
		for (int j = i + 1; j<= N; j++)
		{
			a[j][i] = a[i][j];
		}
	}
	TSP(a, N);
	return 0;
}

运行结果如下:

旅行售货员的最优回路代价:25

旅行售货员的最优回路路径:1 3 2 4 1

    原文作者:分支限界法
    原文地址: https://blog.csdn.net/qq_24059821/article/details/51318265
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞