哈密尔顿回路(旅行售货员问题)的回溯算法


1. 回溯法的基本原理:

回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。用回溯算法解决问题的一般步骤为:

1、定义一个解空间,它包含问题的解。

2、利用适于搜索的方法组织解空间。

3、利用深度优先法搜索解空间。

4、利用限界函数避免移动到不可能产生解的子空间。

问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。

2.旅行售货员问题的回溯算法实现

算法具体实现主要代码如下:

// TravelSaler.cpp : 定义控制台应用程序的入口点。

//

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

#include
"stdafx.h"

#include
<iostream>

#include
<fstream>

#include<stdlib.h>

using
namespace std;

?

ifstream fin("input.txt");

const
int N = 4;//图的顶点数

?

template<class
Type>

class
Traveling

{

????template<class
Type>

????friend
Type TSP(Type **a, int n);

private:

????void Backtrack(int i);

????int n,???????? // 图G的顶点数

????????*x, // 当前解

????????*bestx; // 当前最优解

????Type **a, // 图G的领接矩阵

????????cc, // 当前费用

????????bestc; // 当前最优值

????int NoEdge; // 无边标记

};

?

template <class
Type>

inline
void Swap(Type &a, Type &b);

?

template<class
Type>

Type TSP(Type **a, int n);

?

int main()

{

????cout << "图的顶点个数 n=" << N << endl;

?

????int **a = new
int*[N + 1];

????for (int i = 0; i <= N; i++)

????{

????????a[i] = new
int[N + 1];

????}

?

????cout << "图的邻接矩阵为:" << endl;

?

????for (int i = 1; i <= N; i++)

????{

????????for (int j = 1; j <= N; j++)

????????{

????????????fin >> a[i][j];

????????????cout << a[i][j] << " ";

????????}

????????cout << endl;

????}

????cout << "最短回路的长为:" << TSP(a, N) << endl;

?

????for (int i = 0; i <= N; i++)

????{

????????delete[]a[i];

????}

????delete[]a;

?

????a = 0;

????system("pause");

????return 0;

????

}

?

template<class
Type>

void
Traveling<Type>::Backtrack(int
i)

{

????if (i == n)

????{

????????if (a[x[n - 1]][x[n]] != 0 && a[x[n]][1] != 0 &&

????????????(cc + a[x[n - 1]][x[n]] + a[x[n]][1] < bestc || bestc == 0))

????????{

????????????for (int j = 1; j <= n; j++) bestx[j] = x[j];

????????????bestc = cc + a[x[n - 1]][x[n]] + a[x[n]][1];

????????}

????}

????else

????{

????????for (int j = i; j <= n; j++)

????????{

????????????// 是否可进入x[j]子树?

????????????if (a[x[i - 1]][x[j]] != 0 && (cc + a[x[i - 1]][x[i]] < bestc || bestc == 0))

????????????{

????????????????// 搜索子树

????????????????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]);

????????????}

????????}

????}

}

?

template<class
Type>

Type TSP(Type **a, int
n)

{

????Traveling<Type> Y;

????Y.n = n;

????Y.x = new
int[n + 1];

????Y.bestx = new
int[n + 1];

?

????for (int i = 1; i <= n; i++)

????{

????????Y.x[i] = i;

????}

?

????Y.a = a;

????Y.cc = 0;

????Y.bestc = 0;

?

????Y.NoEdge = 0;

????Y.Backtrack(2);

?

????cout << "最短回路为:" << endl;

????for (int i = 1; i <= n; i++)

????{

????????cout << Y.bestx[i] << " --> ";

????}

????cout << Y.bestx[1] << endl;

?

????delete[] Y.x;

????Y.x = 0;

????delete[] Y.bestx;

?

????Y.bestx = 0;

????return Y.bestc;

}

?

template <class
Type>

inline
void Swap(Type &a, Type &b)

{

????Type temp = a;

????a = b;

????b = temp;

}

其中input.txt的内容为:

0 30 6 4

30 0 5 10

6 5 0 20

4 10 20 0


编译并运行程序。

3.
旅行售货员问题的回溯算法的解空间树以及搜索过程:


(3)算法的时间复杂性和空间复杂性

?算法backtrack在最坏情况下可能需要更新当前最优解O((n-1)!)次,每次更新bestx需计算时间O(n),从而整个算法的计算时间复杂性为O(n!)。?


程序运行结果如下:

?

开始测试时每次都要输入图的邻接矩阵,非常麻烦,后面改为直接从input文件中读取,大大简化了调试过程

时间: 2024-10-11 13:31:25

哈密尔顿回路(旅行售货员问题)的回溯算法的相关文章

旅行商问题(TSP)、最长路径问题与哈密尔顿回路之间的联系(归约)

一,旅行商问题与H回路的联系(H回路 定义为 哈密尔顿回路) 旅行商问题是希望售货员恰好访问每个城市一次,最终回到起始城市所用的费用最低,也即判断图中是否存在一个费用至多为K的回路.(K相当于图中顶点的个数) 由于售货员可以从某个城市到其他任何一个城市.因此,该问题对应的是一个完全图(设为G′).而关于判断哈密尔顿回路的图(设为G)并不一定为完全图,因此,在将哈密尔顿回路问题归约到旅行商问题时,定义一个费用函数(详情参考<算法导论第二版中文版>第626页. 通过这个费用函数,将判断G′是否存在

poj 2288 Islands and Bridges_状态压缩dp_哈密尔顿回路问题

题目链接 题目描写叙述:哈密尔顿路问题.n个点,每个点有权值,设哈密尔顿路为 C1C2...Cn,Ci的权值为Vi,一条哈密尔顿路的值分为三部分计算: 1.每个点的权值之和2.对于图中的每一条CiCi+1,加上Vi*Vi+1 3.对于路径中的连续三个点:CiCi+1Ci+2,若在图中,三点构成三角形,则要加上Vi*Vi+1*Vi+2 求一条汉密尔顿路能够获得的最大值,而且还要输出有多少条这种哈密尔顿路. 这道题的状态感觉不是非常难想,由于依据一般的哈密尔顿路问题,首先想到的是设计二维状态,dp[

哈密尔顿道路与哈密尔顿回路

简介 1857年爱尔兰数学家哈密尔顿发明了"周游世界"玩具,用一个正十二面体的20个顶点表示世界上20个大城市,30条棱代表这些城市之间的道路.要求游戏者从任意一个城市(即顶点)出发,延棱行走经过每个城市一次且只经过一次,最终返回出发地.哈密尔顿将此问题称为周游世界问题,并且作了肯定的回答. 以下是一种走法 与之等价的可以做成平面图,按这个编号走是可行的 哈密尔顿道路与哈密尔顿回路 哈密尔顿道路:通过图G中每个顶点一次且仅一次的道路称作该图的一条哈密尔顿道路. 哈密尔顿回路:通过图G中

【算法】欧拉(回)路与哈密尔顿环

概念 "哈密尔顿回路问题"是访问除原出发结点以外的每个结点一次且仅一次,而"欧拉回路问题"是访问每条边一次且仅一次 欧拉回路与欧拉路 PS:已经判断此图有欧拉路或欧拉回路 #include<iostream> using namespace std; int g[101][101]; int du[101]; int lu[101]; int n,e,l,start,x,y; int maxn,minn=99999; int find(int i) {

哈密尔顿环问题

哈密尔顿环 欧拉回路是指不重复地走过所有路径的回路,而哈密尔顿环是指不重复地走过所有的点,并且最后还能回到起点的回路. 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int num[10001];//求一个点能过到达的边的数量 5 int map[1001][1001]; 6 int jztx[1001]; 7 int vis[1001]; 8 int now=1; 9 int ans[1001];

哈密尔顿环x

欧拉回路是指不重复地走过所有路径的回路,而哈密尔顿环是指不重复地走过所有的点,并且最后还能回到起点的回路. 代码如下: #include<iostream> #include<cstring> using namespace std; const int Maxn=1001; int start,lengt,x,n; bool visited[Maxn],v1[Maxn]; int ans[Maxn],num[Maxn]; int g[Maxn][Maxn]; void print

哈密尔顿环

1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int start,length,x,n; 5 bool visited[101],v1[101]; 6 int ans[101], num[101]; 7 int g[101][101]; 8 void print() { 9 int i; 10 for (i = 1; i <= length; i++) 11 cout << '

图像处理中的数学原理详解(Part7) ——哈密尔顿算子

全文目录请见 图像处理中的数学原理详解(Part1 总纲) http://blog.csdn.net/baimafujinji/article/details/48467225 在前面的部分中我们已经完整地给出了梯度和散度这些数学概念的意义,这些生涩的定义在最初学习的时候很少有人会注意到它们跟图像能有什么联系.然而,随着学习的深入,当真正接触到图像处理算法时,你又不得不承认,梯度.散度这些东西几乎是无处不在的.本节所介绍的内容就是这些概念在图像处理中的最最简单应用之范例.这部分内容与边缘检测技术

POJ 2288 Islands and Bridges 哈密尔顿路 状态压缩DP

找最长的其实是很裸的状态压缩DP,棘手的地方是要统计数量,其实只要再来一个数组存就好. 不过代码比较长,细节要注意的地方毕较多,wa了很多发,还是要仔细啊 用递推和记忆化搜索分别写了一遍 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <