动态规划法回溯法分支限界法求解TSP问题实验报告
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
using 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;
{
if(![i])
{
=;
=+mp[][i];
=i;
=+1;
for(int j=1; j<=n; j++) [j]=[j];
[i]=1;
=gao(tmp);
if<=up)
(tmp);
}
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0; i<=n; i++)
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)
}
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];
scanf("%d",&mp[i][j]);
}
}
egin();
sum+=*it;
it++;
sum+=*it;
}
return sum/2;
}
int gao(node s)
{
int res=*2;
int t1=inf,t2=inf;
for(int i=1; i<=n; i++)
{
if(![i])
{
t1=min(t1,mp[i][]);
TSP问题算法实验报告
指导教师:季晓慧
姓 名:辛瑞乾
学 号:
提交日期:2015年11月
总述2
动态规划法2
算法问题分析2
算法设计2
实现代码2
输入输出截图5
OJ提交截图5
算法优化分析5
回溯法5
算法问题分析5
算法设计6
实现代码6
输入输出截图8
OJ提交截图8
算法优化分析9
分支限界法9
算法问题分析9
算法设计9
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
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];
算法设计
输入:图的代价矩阵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)
算法问题分析
回溯法求解TSP问题,首先把所有的顶点的访问标志初始化为0,然后在解空间树中从根节点出发开始搜索,如果从根节点到当前结点对应一个部分解,即满足上述约束条件,则在当前结点处选择第一棵子树继续搜索,否则,对当前子树的兄弟结点进行搜索,如果当前结点的所有子树都已尝试过并且发生冲突,则回溯到当前结点的父节点。采用邻接矩阵mp[n][n]存储顶点之间边的情况,为避免在函数间传递参数,将数组mp设置为全局变量,设数组x[n]表示哈密顿回路经过的顶点。
Mp[i].clear();
for(int i=1; i<=n; i++)
{
for(int j=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());
}
}
int cnt=+mp[p][]+mp[][p];
node tmp=();
if(cnt<=
{
ans=min(ans,cnt);
return;
}
else
{
up=min(up,cnt);
ans=min(ans,cnt);
continue;
}
}
node tmp;
for(int i=1; i<=n; i++)
动态规划法
算法问题分析
假设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问题的算法如下。
#include <numeric>
#include <iomanip>
#include <bitset>
#百度文库nclude <sstream>
#include <fstream>
#define debug "output for debug\n"
#define pi (acos)
#define eps (1e-8)
}
memset(vis,0,sizeof vis);
vis[1]=1;
up=0;
up+=getup(1,1,up);
low=getlow();
node fir;
=1;
=1;
=1;
for(int i=1; i<=n; i++) [i]=0;
[1]=1;
=0;
=low;
ans=inf;
bfs(fir);
实现代码9
输入输出截图14
OJ提交截图14
算法优化分析14
总结15
总述
TSP问题又称为旅行商问题,是指一个旅行商要历经所有城市一次最后又回到原来的城市,求最短路程或最小花费,解决TSP可以用好多算法,比如蛮力法,动态规划法…具体的时间复杂的也各有差异,本次实验报告包含动态规划法,回溯法以及分支限界法。
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
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]];
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]);
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;
t2=min(t2,mp[][i]);
}
}
res+=t1;
res+=t2;
int tmp;
for(int i=1; i<=n; i++)
{
tmp=inf;
if(![i])
{
it=Mp[i].begin();
res+=*it;
for(int j=1; j<=n; j++)
tmp=min(tmp,mp[j][i]);
res+=tmp;
}
}
return !(res%2) ? (res/2):(res/2+1);
}
void bfs(node s)
{
(s);
while(!())
{
node head=();
();
if==n-1)
{
int p;
for(int i=1; i<=n; i++)
{
if(![i])
{
p=i;
break;
{
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;
#define debug "output for debug\n"
#define pi (acos)
#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
、若数组x[n]已经形成哈密顿路径,则输出数组x[n],算法结束;
、若数组x[n]构成哈密顿路径的部分解,则k=k+1,转步骤3;
、否则,取消顶点x[k]的访问标志,重置x[k],k=k-1,转步骤3。
实现代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#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 Max = 100005;
对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 <map>
#include <stack>
#include <queue>
#include <cctype>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
算法设计
输入:无向图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,转步骤;
}
return 0;
}
输入输出截图
OJ提交截图
算法优化分析
该算法需要对顶点集合{1,2,…,n-1}的每一个子集进行操作,因此时间复杂度为O(2^n)。和蛮力法相比,动态规划法求解TSP问题,把原来的时间复杂度是O(n!)的排列问题,转化为组合问题,从而降低了算法的时间复杂度,但仍需要指数时间。
回溯法
printf("%d\n",ans);
}
return 0;
}
输入输出截图
OJ提交截图
算法优化分析
分支限界法的复杂度是根据数据的不同而不同,搜索的节点越少,复杂度越低,跟目标函数的选择有很大关系。目标函数值的计算也会需要一定时间,比如此文章中的目标函数值求解的复杂度是O(n^2)。当然此算法仍然有可以优化的地方,比如在记录该路径每个叶子结点的孩子结点时可以采用二进制的思想,从而使算法的时间复杂度在下降到当前T/n的数量级,解决COJ1814问题应该不成问题。
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;
{
if(![i])
{
=;
=+mp[][i];
=i;
=+1;
for(int j=1; j<=n; j++) [j]=[j];
[i]=1;
=gao(tmp);
if<=up)
(tmp);
}
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0; i<=n; i++)
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)
}
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];
scanf("%d",&mp[i][j]);
}
}
egin();
sum+=*it;
it++;
sum+=*it;
}
return sum/2;
}
int gao(node s)
{
int res=*2;
int t1=inf,t2=inf;
for(int i=1; i<=n; i++)
{
if(![i])
{
t1=min(t1,mp[i][]);
TSP问题算法实验报告
指导教师:季晓慧
姓 名:辛瑞乾
学 号:
提交日期:2015年11月
总述2
动态规划法2
算法问题分析2
算法设计2
实现代码2
输入输出截图5
OJ提交截图5
算法优化分析5
回溯法5
算法问题分析5
算法设计6
实现代码6
输入输出截图8
OJ提交截图8
算法优化分析9
分支限界法9
算法问题分析9
算法设计9
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
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];
算法设计
输入:图的代价矩阵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)
算法问题分析
回溯法求解TSP问题,首先把所有的顶点的访问标志初始化为0,然后在解空间树中从根节点出发开始搜索,如果从根节点到当前结点对应一个部分解,即满足上述约束条件,则在当前结点处选择第一棵子树继续搜索,否则,对当前子树的兄弟结点进行搜索,如果当前结点的所有子树都已尝试过并且发生冲突,则回溯到当前结点的父节点。采用邻接矩阵mp[n][n]存储顶点之间边的情况,为避免在函数间传递参数,将数组mp设置为全局变量,设数组x[n]表示哈密顿回路经过的顶点。
Mp[i].clear();
for(int i=1; i<=n; i++)
{
for(int j=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());
}
}
int cnt=+mp[p][]+mp[][p];
node tmp=();
if(cnt<=
{
ans=min(ans,cnt);
return;
}
else
{
up=min(up,cnt);
ans=min(ans,cnt);
continue;
}
}
node tmp;
for(int i=1; i<=n; i++)
动态规划法
算法问题分析
假设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问题的算法如下。
#include <numeric>
#include <iomanip>
#include <bitset>
#百度文库nclude <sstream>
#include <fstream>
#define debug "output for debug\n"
#define pi (acos)
#define eps (1e-8)
}
memset(vis,0,sizeof vis);
vis[1]=1;
up=0;
up+=getup(1,1,up);
low=getlow();
node fir;
=1;
=1;
=1;
for(int i=1; i<=n; i++) [i]=0;
[1]=1;
=0;
=low;
ans=inf;
bfs(fir);
实现代码9
输入输出截图14
OJ提交截图14
算法优化分析14
总结15
总述
TSP问题又称为旅行商问题,是指一个旅行商要历经所有城市一次最后又回到原来的城市,求最短路程或最小花费,解决TSP可以用好多算法,比如蛮力法,动态规划法…具体的时间复杂的也各有差异,本次实验报告包含动态规划法,回溯法以及分支限界法。
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
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]];
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]);
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;
t2=min(t2,mp[][i]);
}
}
res+=t1;
res+=t2;
int tmp;
for(int i=1; i<=n; i++)
{
tmp=inf;
if(![i])
{
it=Mp[i].begin();
res+=*it;
for(int j=1; j<=n; j++)
tmp=min(tmp,mp[j][i]);
res+=tmp;
}
}
return !(res%2) ? (res/2):(res/2+1);
}
void bfs(node s)
{
(s);
while(!())
{
node head=();
();
if==n-1)
{
int p;
for(int i=1; i<=n; i++)
{
if(![i])
{
p=i;
break;
{
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;
#define debug "output for debug\n"
#define pi (acos)
#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
、若数组x[n]已经形成哈密顿路径,则输出数组x[n],算法结束;
、若数组x[n]构成哈密顿路径的部分解,则k=k+1,转步骤3;
、否则,取消顶点x[k]的访问标志,重置x[k],k=k-1,转步骤3。
实现代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#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 Max = 100005;
对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 <map>
#include <stack>
#include <queue>
#include <cctype>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
算法设计
输入:无向图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,转步骤;
}
return 0;
}
输入输出截图
OJ提交截图
算法优化分析
该算法需要对顶点集合{1,2,…,n-1}的每一个子集进行操作,因此时间复杂度为O(2^n)。和蛮力法相比,动态规划法求解TSP问题,把原来的时间复杂度是O(n!)的排列问题,转化为组合问题,从而降低了算法的时间复杂度,但仍需要指数时间。
回溯法
printf("%d\n",ans);
}
return 0;
}
输入输出截图
OJ提交截图
算法优化分析
分支限界法的复杂度是根据数据的不同而不同,搜索的节点越少,复杂度越低,跟目标函数的选择有很大关系。目标函数值的计算也会需要一定时间,比如此文章中的目标函数值求解的复杂度是O(n^2)。当然此算法仍然有可以优化的地方,比如在记录该路径每个叶子结点的孩子结点时可以采用二进制的思想,从而使算法的时间复杂度在下降到当前T/n的数量级,解决COJ1814问题应该不成问题。