当前位置:文档之家› 动态规划法,回溯法,分支限界法求解TSP问题实验报告

动态规划法,回溯法,分支限界法求解TSP问题实验报告

TSP问题算法实验报告指导教师:****名:***学号:**********提交日期:2015年11月目录总述 (2)动态规划法 (3)算法问题分析 (3)算法设计 (3)实现代码 (3)输入输出截图 (6)OJ提交截图 (6)算法优化分析 (6)回溯法 (6)算法问题分析 (6)算法设计 (7)实现代码 (7)输入输出截图 (9)OJ提交截图 (9)算法优化分析 (10)分支限界法 (10)算法问题分析 (10)算法设计 (10)实现代码 (10)输入输出截图 (15)OJ提交截图 (15)算法优化分析 (15)总结 (16)总述TSP问题又称为旅行商问题,是指一个旅行商要历经所有城市一次最后又回到原来的城市,求最短路程或最小花费,解决TSP可以用好多算法,比如蛮力法,动态规划法…具体的时间复杂的也各有差异,本次实验报告包含动态规划法,回溯法以及分支限界法。

动态规划法算法问题分析假设n个顶点分别用0~n-1的数字编号,顶点之间的代价存放在数组mp[n][n]中,下面考虑从顶点0出发求解TSP问题的填表形式。

首先,按个数为1、2、…、n-1的顺序生成1~n-1个元素的子集存放在数组x[2^n-1]中,例如当n=4时,x[1]={1},x[2]={2},x[3]={3},x[4]={1,2},x[5]={1,3},x[6]={2,3},x[7]={1,2,3}。

设数组dp[n][2^n-1]存放迭代结果,其中dp[i][j]表示从顶点i经过子集x[j]中的顶点一次且一次,最后回到出发点0的最短路径长度,动态规划法求解TSP问题的算法如下。

算法设计输入:图的代价矩阵mp[n][n]输出:从顶点0出发经过所有顶点一次且仅一次再回到顶点0的最短路径长度1.初始化第0列(动态规划的边界问题)for(i=1;i<n;i++)dp[i][0]=mp[i][0]2.依次处理每个子集数组x[2^n-1]for(i=1;i<n;i++)if(子集x[j]中不包含i)对x[j]中的每个元素k,计算d[i][j]=min{mp[i][k]+dp[k][j-1]};3.输出最短路径长度。

实现代码#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <ctime>#include <iostream>#include <algorithm>#include <string>#include <vector>#include <deque>#include <list>#include <set>#include <map>#include <stack>#include <queue>#include <cctype>#include <numeric>#include <iomanip>#include <bitset>#include <sstream>#include <fstream>#define debug "output for debug\n" #define pi (acos(-1.0))#define eps (1e-8)#define inf 0x3f3f3f3f#define ll long long int#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1 using namespace std;const int mod = 1000000007;const int Max = 100005;int n,mp[20][20],dp[20][40000];int main(){while(~scanf("%d",&n)){int ans=inf;memset(mp,0,sizeof mp);for(int i=0; i<n; i++){for(int j=0; j<n; j++){if(i==j){mp[i][j]=inf;continue;}int tmp;scanf("%d",&tmp);mp[i][j]=tmp;}}int mx=(1<<(n-1));dp[0][0]=0;for(int i=1; i<n; i++){dp[i][0]=mp[i][0];}dp[0][mx-1]=inf;for(int j=1; j<(mx-1); j++){for(int i=1; i<n; i++){if((j&(1<<(i-1)))==0){int x,y=inf;for(int k=1; k<n; k++){if((j&(1<<(k-1)))>0){x=dp[k][(j-(1<<(k-1)))]+mp[i][k];y=min(y,x);}}dp[i][j]=y;}}}dp[0][mx-1]=inf;for(int i=1;i<n;i++)dp[0][mx-1]=min(dp[0][mx-1],mp[0][i]+dp[i][(mx-1)-(1<<(i-1))]);printf("%d\n",dp[0][mx-1]);}return 0;}输入输出截图OJ提交截图算法优化分析该算法需要对顶点集合{1,2,…,n-1}的每一个子集进行操作,因此时间复杂度为O(2^n)。

和蛮力法相比,动态规划法求解TSP问题,把原来的时间复杂度是O(n!)的排列问题,转化为组合问题,从而降低了算法的时间复杂度,但仍需要指数时间。

回溯法算法问题分析回溯法求解TSP问题,首先把所有的顶点的访问标志初始化为0,然后在解空间树中从根节点出发开始搜索,如果从根节点到当前结点对应一个部分解,即满足上述约束条件,则在当前结点处选择第一棵子树继续搜索,否则,对当前子树的兄弟结点进行搜索,如果当前结点的所有子树都已尝试过并且发生冲突,则回溯到当前结点的父节点。

采用邻接矩阵mp[n][n]存储顶点之间边的情况,为避免在函数间传递参数,将数组mp设置为全局变量,设数组x[n]表示哈密顿回路经过的顶点。

算法设计输入:无向图G=(V,E)输出:哈密顿回路1、将顶点数组x[n]初始化为0,标志数组vis[n]初始化为0;2、从顶点0出发构造哈密顿回路:vis[0]=1;x[0]=1;k=1;3、While(k>=1)3.1、x[k]=x[k]+1,搜索下一个顶点。

3.2、若n个顶点没有被穷举完,则执行下列操作3.2.1、若顶点x[k]不在湖密顿回路上并且(x[k-1],x[k])∈E,转步骤3.3;3.2.2、否则,x[k]=x[k]+1,搜索下一个顶点。

3.3、若数组x[n]已经形成哈密顿路径,则输出数组x[n],算法结束;3.4、若数组x[n]构成哈密顿路径的部分解,则k=k+1,转步骤3;3.5、否则,取消顶点x[k]的访问标志,重置x[k],k=k-1,转步骤3。

实现代码#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <ctime>#include <iostream>#include <algorithm>#include <string>#include <vector>#include <deque>#include <list>#include <set>#include <map>#include <stack>#include <queue>#include <cctype>#include <numeric>#include <iomanip>#include <bitset>#include <sstream>#include <fstream>#define debug "output for debug\n"#define pi (acos(-1.0))#define eps (1e-8)#define inf 0x3f3f3f3f#define ll long long int#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1using namespace std;int mp[20][20];int x[30],vis[30];int n,k,cur,ans;void init(){for(int i=0;i<n;i++)for(int j=0;j<n;j++)mp[i][j]=-1;ans=-1;cur=0;for(int i=1;i<=n;i++)x[i]=i;}void dfs(int t){if(t==n){if(mp[x[n-1]][x[n]]!=-1&&(mp[x[n]][1]!=-1)&&(cur+mp[x[n-1]][x[n]]+mp[x[n]][1]<ans||ans==-1)) {for(int i=1;i<=n;i++)vis[i]=x[i];ans=cur+mp[x[n-1]][x[n]]+mp[x[n]][1];}}else{for(int i=t;i<=n;i++){if(mp[x[t-1]][x[i]]!=-1&&(cur+mp[x[t-1]][x[i]]<ans||ans==-1)){swap(x[t],x[i]);cur+=mp[x[t-1]][x[t]];dfs(t+1);cur-=mp[x[t-1]][x[t]];swap(x[t],x[i]);}}}}int main(){while(~scanf("%d",&n)){init();for(int i=1; i<=n; i++){for(int j=1; j<=n; j++){if(i==j)continue;scanf("%d",&mp[i][j]);}}///puts("YES");dfs(2);cout<<ans<<endl;}return 0;}输入输出截图OJ提交截图算法优化分析在哈密顿回路的可能解中,考虑到约束条件xi!=xj(1<=I,j<=n,i!=j),则可能解应该是(1,2,…,n)的一个排列,对应的解空间树种至少有n!个叶子结点,每个叶子结点代表一种可能解。

相关主题