TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx

上传人:b****4 文档编号:17739637 上传时间:2022-12-09 格式:DOCX 页数:21 大小:148.37KB
下载 相关 举报
TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx_第1页
第1页 / 共21页
TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx_第2页
第2页 / 共21页
TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx_第3页
第3页 / 共21页
TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx_第4页
第4页 / 共21页
TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx

《TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx》由会员分享,可在线阅读,更多相关《TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx(21页珍藏版)》请在冰豆网上搜索。

TSP问题分析动态规划分支界限法蛮力法教学文案Word文件下载.docx

某一个点i不经过任意点回到起始点的最短路径和为mp[i][0](默认初始点为0)

dp[i][0]=mp[i][0];

(1<

=i<

n)

点i经过集合S(二进制表示的数为j)的最短路径和为从点i经过集合S中的某一点k后再从该点出发,经过集合S-{k}的最小值。

dp[i][j]=min{mp[i][k]+dp[k][j-(1<

<

(k-1))};

2、贪心法

(1)数据结构

利用贪心法每次取最近距离的函数dfs(u,k,l),u表示当前在顶点u,k表示已经走过了k个点,l表示所经过的路径和。

inq[i]表示顶点i已经走过了。

如果当前在顶点u,则取与顶点u距离最近的点p。

dfs(u,k,l)=dfs(p,k+1,l+mp[u][p])

3、分支限界法

结构体

structnode

{

intvisp[22];

//标记哪些点走了

intst;

//起点

inted;

//终点

intk;

//走过的点数

intsumv;

//经过路径的距离

intlb;

//目标函数的值

booloperator<

(constnode&

p)const

{

returnlb>

p.lb;

}

};

优先级队列

priority_queue<

node>

q;

in()

输入函数。

dfs(intu,intk,intl)

利用贪心法每次取最近距离的函数,u表示当前在顶点u,k表示已经走过了k个点,l表示所经过的路径和。

将贪心法的解作为上界的初始值。

get_lb(nodep)

求对应节点p的目标函数。

main()

主函数。

get_up()

求分支限界法的上界。

get_low()

求分支界限法的下界。

solve()

利用分支限界法求解函数

首先通过贪心法求解的值作为上界,把每个点最近的两条边之和的1/2作为下界。

分支限界法通过设定目标函数,每次从优先级队列中取目标函数的值最小的节点。

先判断是否已经经过了n-1个点,如果已经经过了n-1个点,那么可直接求出最短路径和,并与在队列里的其他节点的目标函数值比较,如果该路径和比其他所有在队列里的节点的目标函数值都小,那么改路径和就是问题的解。

否则,继续计算优先级队列里面的其他节点。

3、源程序及注释:

这里默认顶点的个数小于22。

1、动态规划法

#include<

iostream>

cstdio>

#defineINF9999

usingnamespacestd;

intmp[22][22];

intn;

voidin()

scanf("

%d"

&

n);

for(inti=0;

i<

n;

i++)

for(intj=0;

j<

j++)

if(i==j)

mp[i][j]=INF;

continue;

mp[i][j]);

}

intdp[22][1<

22];

intsolve()

ints=(1<

(n-1));

dp[0][0]=0;

for(inti=1;

dp[i][0]=mp[i][0];

dp[0][(s-1)]=INF;

for(intj=1;

(s-1);

j++)//总共有n-1个点,但不能全部取

i++)//把1~(n-1)这n-1个点,映射为集合对应的二进制数中的0~(n-2)位

if((j&

(1<

(i-1)))==0)//i不在集合中

intm=INF;

for(intk=1;

k<

k++)

(k-1)))>

0)//k在集合中

inttmp=dp[k][(j-(1<

(k-1)))]+mp[i][k];

if(m>

tmp)

m=tmp;

dp[i][j]=m;

dp[0][s-1]=INF;

dp[0][s-1]=min(dp[0][s-1],mp[0][i]+dp[i][(s-1)-(1<

(i-1))]);

returndp[0][s-1];

intmain()

in();

printf("

%d\n"

solve());

return0;

2、贪心法

intinq[22];

i<

=n;

i++)

j<

j++)

intdfs(intu,intk,intl)

if(k==n)returnl+mp[u][1];

intminlen=INF,p;

if(inq[i]==0&

&

minlen>

mp[u][i])/*取与所有点的连边中最小的边*/

minlen=mp[u][i];

p=i;

inq[p]=1;

returndfs(p,k+1,l+minlen);

inq[1]=1;

dfs(1,1,0));

3、分支限界法

//分支限界法

algorithm>

queue>

#defineINF100000

/*n*n的一个矩阵*/

//最少3个点,最多15个点

/*输入距离矩阵*/

intst_p;

//起点的邻接点

inted_p;

//终点的邻接点

intlow,up;

//确定上界

intget_lb(nodep)

intret=p.sumv*2;

//路径上的点的距离

intmin1=INF,min2=INF;

//起点和终点连出来的边

if(p.visp[i]==0&

min1>

mp[i][p.st])

min1=mp[i][p.st];

ret+=min1;

min2>

mp[p.ed][i])

min2=mp[p.ed][i];

ret+=min2;

if(p.visp[i]==0)

min1=min2=INF;

if(min1>

mp[i][j])

min1=mp[i][j];

if(min2>

mp[j][i])

min2=mp[j][i];

ret+=min1+min2;

returnret%2==0?

(ret/2):

(ret/2+1);

voidget_up()

up=dfs(1,1,0);

voidget_low()

low=0;

/*通过排序求两个最小值*/

inttmpA[22];

tmpA[j]=mp[i][j];

sort(tmpA+1,tmpA+1+n);

//对临时的数组进行排序

low+=tmpA[1];

/*贪心法确定上界*/

get_up();

/*取每行最小的边之和作为下界*/

get_low();

/*设置初始点,默认从1开始*/

nodestar;

star.st=1;

star.ed=1;

star.k=1;

i++)star.visp[i]=0;

star.visp[1]=1;

star.sumv=0;

star.lb=low;

/*ret为问题的解*/

intret=INF;

q.push(star);

while(!

q.empty())

nodetmp=q.top();

q.pop();

if(tmp.k==n-1)

/*找最后一个没有走的点*/

intp;

if(tmp.visp[i]==0)

break;

intans=tmp.sumv+mp[p][tmp.st]+mp[tmp.ed][p];

nodejudge=q.top();

/*如果当前的路径和比所有的目标函数值都小则跳出*/

if(ans<

=judge.lb)

ret=min(ans,ret);

/*否则继续求其他可能的路径和,并更新上界*/

else

up=min(up,ans);

ret=min(ret,ans);

/*当前点可以向下扩展的点入优先级队列*/

nodenext;

next.st=tmp.st;

/*更新路径和*/

next.sumv=tmp.sumv+mp[tmp.ed][i];

/*更新最后一个点*/

next.ed=i;

/*更新顶点数*/

next.k=tmp.k+1;

/*更新经过的顶点*/

j++)next.visp[j]=tmp.visp[j];

next.visp[i]=1;

/*求目标函数*/

next.lb=get_lb(next);

/*如果大于上界就不加入队列*/

if(next.lb>

up)continue;

q.push(next);

returnret;

四、运行输出结果:

(贴出程序运行完成时的屏幕截图或者输出文件的内容)

这里采用相同的两组数据进行测试。

样例1:

样例2:

2、贪心法

贪心法只能求局部最优解,局部最优解不一定是全局最优解。

五、调试和运行程序过程中产生的问题及采取的措施:

1、动态规划法中输出错误,通过测试数据进行反复验证,并分块输出局部结果,从而发现问题并解决。

2、贪心法对第二组样例的解不正确,因为局部最优解不一定是全局最优解。

3、分支限界法对于测试样例输出随机值,solve()函数在每次返回的时候结果不一致。

通过反复观察代码,发现循环跳出的条件有问题,应该是当前的解小于或等于队列中的目标函数值才跳出。

六、对算法的程序的讨论、分析,改进设想,其它经验教训:

1、动态规划法算法时间复杂度为O(

),在oj上的测试时间如下:

(oj上的测试样例n最大值为15)

2、贪心法只能求局部最优解,不一定是全局最优解。

所以第二组样例的解不正确。

3、分支限界法的复杂度是根据数据的不同而不同,搜索的节点越少,复杂度越低,跟目标函数的选择有很大关系。

目标函数值的计算也会需要一定时间,比如此文章中的目标函数值求解的复杂度是O(

)。

在oj上的测试时间如下:

在设置节点的时候,用数组标记经过的顶点,visp[i]=1,则说明i点已经经过了,由于是静态分配空间,所以每次创建新的节点,都会增加空间。

所以可以考虑动态分配空间,把不用的节点的空间释放掉。

4、对于顶点少的TSP问题,还可以采用蛮力法。

时间复杂度为O(n!

),但实现起来比较简单,这里使用了stl中生成全全排列的函数next_permutation()。

(测试时限为5000ms)

下面给出蛮力法的代码:

intmp[22][22],n;

#defineINF99999

inta[22],b[22],c[22];

intret=99999;

a[i]=i;

b[i]=i;

c[i]=i;

do

inttmp[22];

tmp[i]=b[a[i]];

intsum=0;

for(inti=2;

sum+=mp[tmp[i-1]][tmp[i]];

sum+=mp[tmp[n]][tmp[1]];

if(sum<

ret)

ret=sum;

i++)c[i]=tmp[i];

}while(next_permutation(a+1,a+1+n));

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 卡通动漫

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1