算法分析与设计 ------ 旅行售货员 (回溯法)

算法分析与设计 ------ 旅行售货员 (回溯法)

一、问题描述
某售货员要到若干城市去推销商品,已知各城市之间的路程,他要选定一条从驻地出发,经过每个城市一遍,最后回到住地的路线,使总的路程最短。
在这里插入图片描述
算法思路
回溯法,序列树, 假设起点为 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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值