目录
题目描述
某售货员要到若干城市去推销商品,已知各城市之间的路程(或旅费)。他要选定一条从驻地出发,经过每个城市一遍,最后回到驻地的路线,使总的路程(或总旅费)最小。
输入格式:
第一行为城市数n
下面n行n列给出一个完全有向图,如 i 行 j 列表示第 i 个城市到第 j 个城市的距离。
输出格式:
一个数字,表示最短路程长度。
输入样例:
3 0 2 1 1 0 2 2 1 0
输出样例:
3
解题思路:
使用dfs回溯算法,搜索所有可能的情况
对于图中样例
3
0 2 1
1 0 2
2 1 0可以作出如下图
而从1号点出发
有如下路径(这并不是所有情况)
1——>2——>3——>1
1——>3——>2——>1
2——>3——>1——>2
2——>1——>3——>2
3——>2——>1——>3
3——>1——>2——>3
另外的还有
1——>2——>1——>3——>1这种
如果当前的权值和已经超过储存的最小权值则会退出递归,需要剪枝,即提前退出
详细代码:
#include<iostream> #include<cstring> using namespace std; const int N=500; int dt[N][N]; int st[N]; int n; int res; int sum; int start; void dfs(int u) { if(sum>res)return ;//如果当前权值大于储存的最小权值就没必要走下去了,剪枝操作 if(u==start){//回到结束点时进行检查是否满足走过所有顶点的条件 bool bj=true; for(int i=1;i<=n;i++) { if(!st[i]) { bj=false;//如果有一个没满足标记为false break; } } if(bj) { res=min(res,sum);//满足走过所有顶点则更新答案 } } for(int i=1;i<=n;i++) { if(i==u)continue; st[i]++;//走这个点即加1走过的次数 sum+=dt[u][i];//加入总权值 dfs(i); sum-=dt[u][i];//减去加入的权值 st[i]--;//回溯返回上一个点,所以当前点被视为少走了一次 } } signed main() { cin>>n; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cin>>dt[i][j]; res+=dt[i][j];//最大值不会超过所有边权值的和 } } for(int i=1;i<=n;i++) { start=i;//记录开始点 st[i]++; sum=0; dfs(i); st[i]--; } cout<<res<<endl; return 0; }