回溯法 5.1TSP之货郎担问题
Posted 天地一扁舟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回溯法 5.1TSP之货郎担问题相关的知识,希望对你有一定的参考价值。
/*
货郎担问题:
四个顶点的货郎担问题。求从顶点1出发,
最后回到顶点1的最短路线。
v1 v2 v3 v4
v1 无穷 无穷 1 7
v2 8 无穷 5 1
v3 7 2 无穷 1
v4 2 5 3 无穷
算法分析:
因为是采用回溯法来做,肯定是递归,然后还需要现场清理。
要设置一个二维数组来标识矩阵内容,然后回溯还需要设计
一个二维标记数组来剪枝,设定一个目标变量,初始为无穷大,
后续如果有比目标变量值小的就更新。剪枝的条件就是如果走到当前节点的耗费值>=目标变量,就直接不再往下面走,
向上走。
深度优先 = 递归
递归基:如果到达叶子节点的上一个节点,那么就进行是否更新的判断
递归步:如果没有到达叶子节点,就进行剪枝操作,判断能否进入下一个节点,如果能,更新最优值
输入:
4
0 0 1 7
8 0 5 1
7 2 0 1
2 5 3 0
输出:
1 3 2 4 1
6
*/
/*
关键:
1 //递归基:如果已经遍历到叶子节点的上一层节点,i标识递归深度
if(i == g_n)
//判断累加和是否超过最大值,如果有0,应该排除;满足这个条件,才打印
if((g_iArr[pArr[i-1]][pArr[i]] != 0) && (g_iArr[pArr[g_n]][1] != 0) &&
(g_iCurResult + g_iArr[pArr[i-1]][pArr[i]] + g_iArr[pArr[g_n]][1] < g_iResult ))
g_iResult = g_iCurResult + g_iArr[pArr[i-1]][pArr[i]] + g_iArr[pArr[g_n]][1];
//用当前最优路径去更新最优路径,防止下一次没有
for(int k = 1 ; k <= g_n ; k++)
g_iBestPath[k] = pArr[k];
2 //递归步:判断能否进入子树,需要尝试每一个节点
else
//尝试不同的组合
for(int j = i ; j <= g_n ; j++)
//判断能否进入子树:如果当前值+下一个连线值的和 < 最优值,就进入,0要pass
if( (g_iArr[pArr[i-1]][pArr[j]] != 0) && (g_iCurResult + g_iArr[ pArr[i-1] ][ pArr[j] ] < g_iResult) )
3 //交换i与j,则i为当前可以尝试的范围
//为完成后面k个元素的排列,逐一对数组第n-k~n个元素互换。数组第一个元素为1,生成后面n-1个元素的排列
//数组第一个元素与第二个元素互换,第一个元素为2,第2个元素为1,生成后面的n-1个元素的排列...
swap(&pArr[i],&pArr[j]);
//更新当前累加值,是i-1与i的
g_iCurResult += g_iArr[ pArr[i-1] ][ pArr[i] ];
//递归
backTrace(i+1,pArr);
//回溯,清空累加值;能够走到这里,说明上述结果不是最优解,需要向求解树上一层回退
g_iCurResult -= g_iArr[pArr[i-1]][ pArr[i] ];
swap(&pArr[i],&pArr[j]);
*/
#include <iostream>
#include <stdio.h>
const int MAXSIZE = 100;
const int MAX = 1000000000;
int g_iArr[MAXSIZE][MAXSIZE];//邻接矩阵
int g_iResult;//存放最优解
int g_iPath[MAXSIZE];//存放最优路径上
int g_n;//元素个数
int g_iCurResult;//当前累加路径和
int g_iBestPath[MAXSIZE];//还需要设置一个数组,用来保存最优解
void swap(int* pI,int* pJ)
int iTemp = *pI;
*pI= *pJ;
*pJ = iTemp;
void printResult(int n,int* pArr)
printf("%d\\n",g_iResult);
for(int i = 1 ; i <= n ; i++)
if( i != 1)
printf(" %d",pArr[i]);
else
printf("%d",pArr[i]);
printf(" 1\\n");
//可以做成字符串全排列的性质track(int i,int* pArr,int* pResult),其中pArr是用于存放最优解的路径
void backTrace(int i,int* pArr)
//递归基:如果已经遍历到叶子节点的上一层节点
if(i == g_n)
//判断累加和是否超过最大值,如果有0,应该排除;满足这个条件,才打印
if((g_iArr[pArr[i-1]][pArr[i]] != 0) && (g_iArr[pArr[g_n]][1] != 0) &&
(g_iCurResult + g_iArr[pArr[i-1]][pArr[i]] + g_iArr[pArr[g_n]][1] < g_iResult ))
g_iResult = g_iCurResult + g_iArr[pArr[i-1]][pArr[i]] + g_iArr[pArr[g_n]][1];
//用当前最优路径去更新最优路径,防止下一次没有
for(int k = 1 ; k <= g_n ; k++)
g_iBestPath[k] = pArr[k];
//递归步:判断能否进入子树,需要尝试每一个节点
else
//尝试不同的组合
for(int j = i ; j <= g_n ; j++)
//判断能否进入子树:如果当前值+下一个连线值的和 < 最优值,就进入,0要pass
if( (g_iArr[pArr[i-1]][pArr[j]] != 0) && (g_iCurResult + g_iArr[ pArr[i-1] ][ pArr[j] ] < g_iResult) )
//交换i与j,则i为当前可以尝试的范围
//为完成后面k个元素的排列,逐一对数组第n-k~n个元素呼唤。数组第一个元素为1,生成后面n-1个元素的排列
//数组第一个元素与第二个元素互换,第一个元素为2,第2个元素为1,生成后面的n-1个元素的排列...
swap(&pArr[i],&pArr[j]);
//更新当前累加值,是i-1与i的
g_iCurResult += g_iArr[ pArr[i-1] ][ pArr[i] ];
//递归
backTrace(i+1,pArr);
//回溯,清空累加值;能够走到这里,说明上述结果不是最优解,需要向求解树上一层回退
g_iCurResult -= g_iArr[pArr[i-1]][ pArr[i] ];
swap(&pArr[i],&pArr[j]);
void process()
//初始化
while(EOF != scanf("%d",&g_n))
//获取输入
for(int i = 1 ; i <= g_n ; i++)
for(int j = 1 ; j <= g_n ; j++)
scanf("%d",&g_iArr[i][j]);
//初始化根节点,最优路径初始化
for(int j = 1 ; j <= g_n ; j++)
g_iPath[j] = j;
g_iResult = MAX;
g_iCurResult = 0;
backTrace(2,g_iPath);
printResult(g_n,g_iBestPath);
int main(int argc,char* argv[])
process();
getchar();
return 0;
以上是关于回溯法 5.1TSP之货郎担问题的主要内容,如果未能解决你的问题,请参考以下文章
matlab解决TSP问题(货郎担问题,旅行商问题)的模拟退火算法