动态规划法回溯法分支限界法求解TSP问题实验报告Word下载.docx
《动态规划法回溯法分支限界法求解TSP问题实验报告Word下载.docx》由会员分享,可在线阅读,更多相关《动态规划法回溯法分支限界法求解TSP问题实验报告Word下载.docx(13页珍藏版)》请在冰豆网上搜索。
![动态规划法回溯法分支限界法求解TSP问题实验报告Word下载.docx](https://file1.bdocx.com/fileroot1/2022-11/29/6c2b5342-ddef-491b-882f-160cde058fad/6c2b5342-ddef-491b-882f-160cde058fad1.gif)
for(i=1;
i<
n;
i++)
dp[i][0]=mp[i][0]
2.依次处理每个子集数组x[2^n-1]
if(子集x[j]中不包含i)
对x[j]中的每个元素k,计算d[i][j]=min{mp[i][k]+dp[k][j-1]};
3.输出最短路径长度。
实现代码
#include<
cstdio>
cstdlib>
cstring>
cmath>
ctime>
iostream>
algorithm>
string>
vector>
deque>
list>
set>
map>
stack>
queue>
cctype>
numeric>
iomanip>
bitset>
sstream>
fstream>
#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<
i++)
for(intj=0;
j<
j++)
if(i==j)
mp[i][j]=inf;
continue;
}
inttmp;
scanf("
tmp);
mp[i][j]=tmp;
intmx=(1<
(n-1));
dp[0][0]=0;
for(inti=1;
dp[i][0]=mp[i][0];
dp[0][mx-1]=inf;
for(intj=1;
(mx-1);
if((j&
(1<
(i-1)))==0)
intx,y=inf;
for(intk=1;
k<
k++)
(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]=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。
intmp[20][20];
intx[30],vis[30];
intn,k,cur,ans;
voidinit()
j<
j++)
mp[i][j]=-1;
ans=-1;
cur=0;
=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]<
ans||ans==-1))
vis[i]=x[i];
ans=cur+mp[x[n-1]][x[n]]+mp[x[n]][1];
else
for(inti=t;
if(mp[x[t-1]][x[i]]!
(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]];
init();
mp[i][j]);
egin();
sum+=*it;
it++;
returnsum/2;
intgao(nodes)
intres=*2;
intt1=inf,t2=inf;
if(!
[i])
t1=min(t1,mp[i][]);
t2=min(t2,mp[][i]);
res+=t1;
res+=t2;
tmp=inf;
it=Mp[i].begin();
res+=*it;
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;
p=i;
break;
intcnt=+mp[p][]+mp[][p];
nodetmp=();
if(cnt<
=
ans=min(ans,cnt);
return;
up=min(up,cnt);
nodetmp;
=;
=+mp[][i];
=i;
=+1;
j++)[j]=[j];
[i]=1;
=gao(tmp);
if<
=up)
(tmp);
Mp[i].clear();
if(i!
=j)
Mp[i].push_back(mp[i][j]);
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;
i++)[i]=0;
[1]=1;
=0;
=low;
ans=inf;
bfs(fir);
ans);
分支限界法的复杂度是根据数据的不同而不同,搜索的节点越少,复杂度越低,跟目标函数的选择有很大关系。
目标函数值的计算也会需要一定时间,比如此文章中的目标函数值求解的复杂度是O(n^2)。
当然此算法仍然有可以优化的地方,比如在记录该路径每个叶子结点的孩子结点时可以采用二进制的思想,从而使算法的时间复杂度在下降到当前T/n的数量级,解决COJ1814问题应该不成问题。
总结
TSP问题在很多地方都可以运用到,并且好多问题都是由TSP问题延伸和发展的,也可以称之为TSP问题,不过其思路大致相似,于是我们可以运用已学过的算法对其进行解决。
我在学习算法课以前的TSP问题大都用动态规划以及回溯法,究其时间复杂度以及代码的复杂度比较低,思路比较清晰,在解决此类延伸问题时容易调试和修改。
学完算法后最有感触的一点就是,算法的精髓并不在于其方式方法,而在于其思想思路。
有了算法的思想,那么潜移默化中问题就可以得到解决。