算法分析与设计 ------ 旅行售货员 (回溯法)
一、问题描述
某售货员要到若干城市去推销商品,已知各城市之间的路程,他要选定一条从驻地出发,经过每个城市一遍,最后回到住地的路线,使总的路程最短。
算法思路
回溯法,序列树, 假设起点为 1。
算法开始时 x = [1, 2, 3, …, n]
x[1 : n]有两重含义 x[1 : i]代表前 i 步按顺序走过的城市, x[i + 1 : n]代表还未经过的城市。利用Swap函数进行交换位置。
若当前搜索的层次i = n 时,处在排列树的叶节点的父节点上,此时算法检查图G是否存在一条从顶点x[n-1] 到顶点x[n] 有一条边,和从顶点x[n] 到顶点x[1] 也有一条边。若这两条边都存在,则发现了一个旅行售货员的回路即:新旅行路线),算法判断这条回路的费用是否优于已经找到的当前最优回路的费用bestcost,若是,则更新当前最优值bestcost和当前最优解bestx。
若i < n 时,检查x[i - 1]至x[i]之间是否存在一条边, 若存在,则x [1 : i ] 构成了图G的一条路径,若路径x[1: i] 的耗费小于当前最优解的耗费,则算法进入排列树下一层,否则剪掉相应的子树。
就是利用dfs思想进行深度优先搜索并不断剪枝,若途中遇到超出最优解则直接减去剩下枝,节省计算次数优化路径。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,g[100][100],bestx[10],best,x[10],now;
void dfs(int k){
if(k == n){
if(g[x[k - 1]][x[k]] != 0 && g[x[k]][1] != 0 &&
(now + g[x[k - 1]][x[k]] + g[x[k]][1] < best || best == 0)){
for (int i = 1; i < n + 1; i++){
bestx[i] = x[i];
}
best = now + g[x[k - 1]][x[k]] + g[x[k]][1];
}
return;
}
for(int i = k; i < n; i++){
if (g[x[k - 1]][x[i]] != 0 && (now + g[x[k - 1]][x[i]] < best || best == 0)){
swap(x[i],x[k]);
now+=g[x[k - 1]][x[k]];
dfs(k+1);
swap(x[i],x[k]);
now-=g[x[k - 1]][x[k]];
}
}
}
void cins(){
cin>>n>>m;
for(int i = 1; i<=n; i++){
x[i] = i;
}
for(int i = 0; i<m; i++){
int a,b,c;
cout<<"请输入城市序号及其路径长度:"<<endl;
cin>>a>>b>>c;
g[a][b] = c,g[b][a] = c;
}
}
void print(){
cout<<""<<best<<endl;
for(int i=1;i<=n;i++){
cout<<bestx[i]<<" ";
}
cout<<bestx[1];
}
int main(){
cins();
dfs(2);
print();
}