动态规划法回溯法分支限界法求解TSP问题实验报告.docx
- 文档编号:11065439
- 上传时间:2023-02-24
- 格式:DOCX
- 页数:15
- 大小:18.28KB
动态规划法回溯法分支限界法求解TSP问题实验报告.docx
《动态规划法回溯法分支限界法求解TSP问题实验报告.docx》由会员分享,可在线阅读,更多相关《动态规划法回溯法分支限界法求解TSP问题实验报告.docx(15页珍藏版)》请在冰豆网上搜索。
动态规划法回溯法分支限界法求解TSP问题实验报告
TSP问题算法实验报告
指导教师:
季晓慧
姓名:
辛瑞乾
学号:
提交日期:
2015年11月
总述2
动态规划法2
算法问题分析2
算法设计2
实现代码2
输入输出截图5
OJ提交截图5
算法优化分析5
回溯法5
算法问题分析5
算法设计6
实现代码6
输入输出截图8
OJ提交截图8
算法优化分析9
分支限界法9
算法问题分析9
算法设计9
实现代码9
输入输出截图14
OJ提交截图14
算法优化分析14
总结15
总述
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 dp[i][0]=mp[i][0] 2.依次处理每个子集数组x[2^n-1] for(i=1;i if(子集x[j]中不包含i) 对x[j]中的每个元素k,计算d[i][j]=min{mp[i][k]+dp[k][j-1]}; 3.输出最短路径长度。 实现代码 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #definedebug"outputfordebug\n" #definepi(acos) #defineeps(1e-8) #defineinf0x3f3f3f3f #definelllonglongint #definelsonl,m,rt<<1 #definersonm+1,r,rt<<1|1 usingnamespacestd; constintMax=100005; intn,mp[20][20],dp[20][40000]; intmain() { while(~scanf("%d",&n)) { intans=inf; memset(mp,0,sizeofmp); for(inti=0;i { for(intj=0;j { if(i==j) { mp[i][j]=inf; continue; } inttmp; scanf("%d",&tmp); mp[i][j]=tmp; } } intmx=(1<<(n-1)); dp[0][0]=0; for(inti=1;i { dp[i][0]=mp[i][0]; } dp[0][mx-1]=inf; for(intj=1;j<(mx-1);j++) { for(inti=1;i { if((j&(1<<(i-1)))==0) { intx,y=inf; for(intk=1;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(inti=1;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]); } return0; } 输入输出截图 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) 、x[k]=x[k]+1,搜索下一个顶点。 、若n个顶点没有被穷举完,则执行下列操作 ∈E,转步骤; 、若数组x[n]已经形成哈密顿路径,则输出数组x[n],算法结束; 、若数组x[n]构成哈密顿路径的部分解,则k=k+1,转步骤3; 、否则,取消顶点x[k]的访问标志,重置x[k],k=k-1,转步骤3。 实现代码 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #definedebug"outputfordebug\n" #definepi(acos) #defineeps(1e-8) #defineinf0x3f3f3f3f #definelllonglongint #definelsonl,m,rt<<1 #definersonm+1,r,rt<<1|1 usingnamespacestd; intmp[20][20]; intx[30],vis[30]; intn,k,cur,ans; voidinit() { for(inti=0;i for(intj=0;j mp[i][j]=-1; ans=-1;cur=0; for(inti=1;i<=n;i++)x[i]=i; } voiddfs(intt) { 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] { for(inti=1;i<=n;i++) vis[i]=x[i]; ans=cur+mp[x[n-1]][x[n]]+mp[x[n]][1]; } } else { for(inti=t;i<=n;i++) { if(mp[x[t-1]][x[i]]! =-1&&(cur+mp[x[t-1]][x[i]] { 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]); } } } } intmain() { while(~scanf("%d",&n)) { init(); for(inti=1;i<=n;i++) { for(intj=1;j<=n;j++) { if(i==j) continue; scanf("%d",&mp[i][j]); } } egin(); sum+=*it; it++; sum+=*it; } returnsum/2; } intgao(nodes) { intres=*2; intt1=inf,t2=inf; for(inti=1;i<=n;i++) { if(! [i]) { t1=min(t1,mp[i][]); t2=min(t2,mp[][i]); } } res+=t1; res+=t2; inttmp; for(inti=1;i<=n;i++) { tmp=inf; if(! [i]) { it=Mp[i].begin(); res+=*it; for(intj=1;j<=n;j++) tmp=min(tmp,mp[j][i]); res+=tmp; } } return! (res%2)? (res/2): (res/2+1); } voidbfs(nodes) { (s); while(! ()) { nodehead=(); (); if==n-1) { intp; for(inti=1;i<=n;i++) { if(! [i]) { p=i; break; } } intcnt=+mp[p][]+mp[][p]; nodetmp=(); if(cnt<= { ans=min(ans,cnt); return; } else { up=min(up,cnt); ans=min(ans,cnt); continue; } } nodetmp; for(inti=1;i<=n;i++) { if(! [i]) { =; =+mp[][i]; =i; =+1; for(intj=1;j<=n;j++)[j]=[j]; [i]=1; =gao(tmp); if<=up) (tmp); } } } } intmain() { while(~scanf("%d",&n)) { for(inti=0;i<=n;i++) Mp[i].clear(); for(inti=1;i<=n;i++) { for(intj=1;j<=n;j++) { if(i! =j) { scanf("%d",&mp[i][j]); Mp[i].push_back(mp[i][j]); } else mp[i][j]=inf; } sort(Mp[i].begin(),Mp[i].end()); } memset(vis,0,sizeofvis); vis[1]=1; up=0; up+=getup(1,1,up); low=getlow(); nodefir; =1; =1; =1; for(inti=1;i<=n;i++)[i]=0; [1]=1; =0; =low; ans=inf; bfs(fir); printf("%d\n",ans); } return0; } 输入输出截图 OJ提交截图 算法优化分析 分支限界法的复杂度是根据数据的不同而不同,搜索的节点越少,复杂度越低,跟目标函数的选择有很大关系。 目标函数值的计算也会需要一定时间,比如此文章中的目标函数值求解的复杂度是O(n^2)。 当然此算法仍然有可以优化的地方,比如在记录该路径每个叶子结点的孩子结点时可以采用二进制的思想,从而使算法的时间复杂度在下降到当前T/n的数量级,解决COJ1814问题应该不成问题。 总结 TSP问题在很多地方都可以运用到,并且好多问题都是由TSP问题延伸和发展的,也可以称之为TSP问题,不过其思路大致相似,于是我们可以运用已学过的算法对其进行解决。 我在学习算法课以前的TSP问题大都用动态规划以及回溯法,究其时间复杂度以及代码的复杂度比较低,思路比较清晰,在解决此类延伸问题时容易调试和修改。 学完算法后最有感触的一点就是,算法的精髓并不在于其方式方法,而在于其思想思路。 有了算法的思想,那么潜移默化中问题就可以得到解决。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 动态 规划 回溯 分支 限界 求解 TSP 问题 实验 报告