旅行售货员问题-回溯法
问题描述
某售货员要到若干城市去推销商品,已知各城市之间的路程,他要选定一条从驻地出发,经过每个城市一遍,最后回到住地的路线,使总的路程最短。
结果为: 1 3 2 4 1
算法描述
回溯法,序列树, 假设起点为 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] 的耗费小于当前最优解的耗费,则算法进入排列树下一层,否则剪掉相应的子树。
递归回溯
- 回溯法对解空间作深度优先搜索
- 通常用递归方法实现回溯法
void backtrack (int t)
{if (t>n) output(x);// t>n时已搜索到一个叶结点, output(x)对得到的可行解x进行记录或输出处理.else{ for (int i=f(n,t);i<=g(n,t);i++) { // 函数f和g分别表示在当前扩展结点处未搜索子树的起止编号. x[t]=h(i); //h(i)表示在当前扩展结点处x[t]的第i个可选值if (constraint(t)&&bound(t)) backtrack(t+1);} //for循环结束后, 已搜索遍当前扩展结点的所有未搜索子树.}
} //Backtrack(t)执行完毕, 返回t-1层继续执行, 对未测试过的x[t-1]的值继续搜索.
- if (Constraint(t)&&Bound(t) ) Backtrack(t + 1);if语句含义:Constraint(t)和Bound(t)表示当前扩展节点处的约束函数和限界函数。
- Constraint(t): 返回值为true时,在当前扩展节点处x[1:t]的取值问题的约束条件,否则不满足问题的约束条件,可剪去相应的子树
- Bound(t): 返回的值为true时,在当前扩展节点处x[1:t]的取值为时目标函数越界,还需由Backtrack(t+1)对其相应的子树做进一步搜索。否则,当前扩展节点处x[1:t]的取值是目标函数越界,可剪去相应的子树
- for循环作用:搜索遍当前扩展的所有未搜索过的子树。
- 递归出口:Backtrack(t)执行完毕,返回t-1层继续执行,对还没有测试过的x[t-1]的值继续搜索。当t=1时,若以测试完x[1]的所有可选值,外层调用就全部结束。
迭代回溯
采用树的非递归深度优先遍历算法,可将回溯法表示为一个非递归迭代过程。
void iterativeBacktrack ( )
{int t=1;while (t>0) {if (f(n,t)<=g(n,t)) for (int i=f(n,t);i<=g(n,t);i++) {// 函数f和g分别表示在当前扩展结点处未搜索子树的起止编号.x[t]=h(i);if (constraint(t)&&bound(t)) {if (solution(t)) output(x); //solution(t)判断当前扩展结点处是否已得到问题的一个可行解 else t++;} //solution(t)为假,则仅得到一个部分解,需继续纵深搜索}else t--;} //while循环结束后,完成整个回溯搜索过程
}
子集树与排列树
子集树
: 所给的问题是从n个元素的集合中找出满足某种性质的子集时, 相应的解空间称为子集树.
子集树通常有2n个叶结点, 遍历子集树的任何算法均需Ω(2n)的计算时间.
例如: 0-1背包问题的解空间为一棵子集树.
排列树
: 当所给的问题是确定n个元素满足某种性质的排列时, 相应的解空间称为排列树.
排列树通常有(n-1)!个叶结点, 遍历排列树需要Ω(n!)的计算时间.
例如: 旅行售货员问题的解空间为一棵排列树
.
代码实现
#include <bits/stdc++.h>
using namespace std;
const int max_ = 0x3f3f3f; //定义一个最大值
const int NoEdge = -1; //两个点之间没有边
int citynum; //城市数
int edgenum; //边数
int currentcost; //记录当前的路程
int bestcost; //记录最小的路程(最优)
int Graph[100][100]; //图的边距记录
int x[100]; //记录行走顺序
int bestx[100]; //记录最优行走顺序void InPut()
{int pos1, pos2, len; //点1 点2 距离cout<<"请输入城市数和边数(c e):";cin>>citynum>>edgenum;memset(Graph, NoEdge, sizeof(Graph));cout<<"请输入两座城市之间的距离(p1 p2 l):"<<endl;for(int i = 1; i <= edgenum; ++i){cin>>pos1>>pos2>>len;Graph[pos1][pos2] = Graph[pos2][pos1] = len;}
}//初始化
void Initilize()
{currentcost = 0;bestcost = max_;for(int i = 1; i <= citynum; ++i){x[i] = i;}
}void Swap(int &a, int &b)
{int temp;temp = a;a = b;b = temp;
}void BackTrack(int i) //这里的i代表第i步去的城市而不是代号为i的城市
{if(i == citynum){//进行一系列判断,注意的是进入此步骤的层数应是叶子节点的父节点,而不是叶子节点if(Graph[x[i - 1]][x[i]] != NoEdge && Graph[x[i]][x[1]] != NoEdge && (currentcost + Graph[x[i - 1]][x[i]] + Graph[x[i]][x[1]] < bestcost || bestcost == max_)){//最小(优)距离=当前的距离+当前城市到叶子城市的距离+叶子城市到初始城市的距离bestcost = currentcost + Graph[x[i - 1]][x[i]] + Graph[x[i]][x[1]];for(int j = 1; j <= citynum; ++j)bestx[j] = x[j];}}else{for(int j = i; j <= citynum; ++j){if(Graph[x[i - 1]][x[j]] != NoEdge && (currentcost + Graph[x[i - 1]][x[j]] < bestcost || bestcost == max_)){Swap(x[i], x[j]); //这里i 和 j的位置交换了, 所以下面的是currentcost += Graph[x[i - 1]][x[i]];currentcost += Graph[x[i - 1]][x[i]];BackTrack(i + 1); //递归进入下一个城市currentcost -= Graph[x[i - 1]][x[i]];Swap(x[i], x[j]);}}}
}void OutPut()
{cout<<"最短路程为:"<<bestcost<<endl;cout << "路线为:" << endl;for(int i = 1; i <= citynum; ++i)cout << bestx[i] << " ";cout << "1" << endl;
}int main()
{InPut();Initilize();BackTrack(2);OutPut();
}
样例测试
以前面的样例示范
输入
请输入城市数和边数(c e):4 6
请输入两座城市之间的距离(p1 p2 l):
1 2 30
1 3 6
1 4 4
2 4 10
2 3 5
3 4 20
输出
最短路程为:25
路线为:
1 3 2 4 1
旅行售货员问题-回溯法相关推荐
- 回溯子集树与排列树——装载问题旅行售货员问题(算法设计课题)
*对回溯法不是很理解的请移步博客http://blog.csdn.net/sm9sun/article/details/53244484 掌握了回溯法以后,我们给出两种定义: 当所给问题是从n个元素的 ...
- [回溯算法] 五大常用算法之回溯法
算法入门6:回溯法 一. 回溯法 – 深度优先搜素 1. 简单概述 回溯法思路的简单描述是:把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解 ...
- 五大常用算法之回溯法详解及经典例题
一. 回溯法 – 深度优先搜素 1. 简单概述 回溯法思路的简单描述是:把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解或者最优解. 基本思 ...
- java 着色问题 回溯算法,C语言使用回溯法解旅行售货员问题与图的m着色问题
旅行售货员问题 1.问题描述: 旅行售货员问题又称TSP问题,问题如下:某售货员要到若干个城市推销商品,已知各城市之间的路程(或旅费),他要选定一条从驻地出发,经过每个城市一遍最后回到驻地的路线,使总 ...
- 回溯法——旅行售货员问题
旅行售货员问题即给几个地点,相互之间有路径,有每个路径对应的消耗的费用.我们将起点设为1,其他地点设为2,3,4-n.我们起初将所有路径费用都设置成∞,然后再输入 相通路径的费用,再更新费用值.我们以 ...
- 回溯法----旅行售货员问题
一.问题 同文章 <分支限界法----旅行售货员问题> 二.代码实现 程序实现了 递归回溯 解决该问题 迭代回溯算法仍在考虑中... /************************** ...
- 回溯法、分支限界法两种思想帮你轻松搞定旅行售货员问题(TSP)
问题描述 某售货员要到若干城市去推销商品,已知各城市之间的路线(或旅费).要选定一条从驻地出发,经过每个城市一遍,最后回到驻地的路线,使总的路程(或总旅费)最小.本文只考虑4个城市的情况,下面这个带权 ...
- 【算法导论07】回溯法-旅行售货员问题
07回溯法-旅行售货员问题 问题描述: 已知有m个城市,城市之间由n条不同长度的道路相连.一个售货员从一座城市出发,途径所有城市,并最终回到原点,设计算法计算售货员所走的最短路径结点. 问题分析: 从 ...
- 算法设计与分析——回溯法——旅行售货员问题
#include<iostream> #include<bits/stdc++.h> using namespace std; const int noEdge=65535; ...
最新文章
- 如何使用MATLAB绘制不同类型的二维图形
- gRPC学习记录(二)--Hello World
- [GO语言基础] 三.变量声明、数据类型、标识符及编程练习12题
- ORA-28056:Writing audit records to Windows Even...
- Dubbo的发展历史
- WebAPI(part9)--下拉菜单及留言案例
- mysql 数学函数
- powerpoint文字教程
- 在pocket pc 2003上播放声音
- Android图形显示系统——下层显示1:基础知识与相关文件
- c语言文件读入到链表函数fscanf,【求解答】c关于把文件数据放进链表,并将链表遍历...
- 几种常见的 Kafka 集群监控工具
- 如何使用中国知网查询文献,并自动生成参考文献格式引文?
- deepin恢复出厂_初始化 - deepin Wiki
- kali-linux-2022 下载/系统/权限/中文/配置/换源等问题一次解决
- ZYNQ启动流程之分析BootRoM
- php ses 发送邮件,Amazon SES – 通过PHP sdk发送HTML邮件
- 【socket】socket介绍-socket与http服务通信
- c 语言 如何设置串口波特率,串口自动波特率设置程序
- 1万的android手机推荐,Vertu推天价Android手机:入门级售价1万美元