🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 问题描述 > 已给一个n个点的完全图,每条边都有一个权值。求总权值最小的经过每个顶点正好一次的封闭回路。 假设有如下TSP问题: ![](https://box.kancloud.cn/2016-06-03_5750fa8e482a5.PNG) 计算从顶点1出发,依次经过剩下所有的顶点,最后回到顶点1的最小权值。 * 穷举法: 所有构成环路的情况如下: 1-2-3-4 1-2-4-3 1-3-2-4 1-3-4-2 1-4-2-3 1-4-3-2 我们可以将这个解空间组织成一棵树,从树的根节点到任一结点的路径定义了图的一条回路。如图,从A到L的路径上边的标号组成了一条路线,即1,2,3,4。图中的每一条路线对应这个解空间中的一个解,所以解空间树的结点个数为**(n-1)!** ![](https://box.kancloud.cn/2016-06-03_5750fa8e61be9.PNG) 注意: 1. 该树是一棵排列树。 2. 最后到达叶子结点时,需要加上由叶子结点回到根节点的权值。 遍历: 使用回溯法时,从解空间树的根节点A出发,搜索至B,C,F,L。在叶子结点L处记录找到的路线1,2,3,4,1.该路线的花费为59。从叶子结点返回到F处。由于F处没有可扩展的结点,算法又返回到结点C处。结点C称为新扩展结点,由新扩展结点,算法再移至结点G后又移至结点M,得到路线1,2,4,3,1。得到的费用为66,比之前费用大,故删除该结点。 依次方法算法继续搜索遍整个解空间,最终得到最小权值路线。 # 算法设计 #代码实现-1 ``` #include <stdio.h> int a[4][4] = { {0,30,6,4}, {30,0,5,10}, {6,5,0,20}, {4,10,20,0} }; int x[3] = {1,2,3}; //顺序 int cc; //临时值 int n = 4; void swap(int *a,int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; } backtrack(int i) { int j; if(i == n) { //printf("%d-",cc+a[x[n-1]][x[n]]+a[x[n]][1]); }else { for(j=i;j<n;j++) { swap(&x[i],&x[j]); cc += a[x[i-1]][x[i]]; printf("%d--",cc); backtrack(i+1); cc -= a[x[i-1]][x[i]]; swap(&x[i],&x[j]); } } } int main(void) { backtrack(1); return 0; } ```