分支界限算法--旅行商问题2

假期 2020.01.22

题目描述

见回溯算法–旅行商问题1


算法分析

此篇采用分支界限算法解决该问题,相比较前一篇的回溯算法–旅行商问题1,此处使用Bfs搜索加优先队列的方式。
注: 优先队列容器与队列一样,只能从队尾插入元素,从队首删除元素。但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。而此处设置最小的每次先出队列。

  1. 设置二维数组存储关系
  2. 初始化解向量,即选择方案都为零,并且将最优值赋值为无穷
  3. 定义优先队列:
int operator <(const Node& a, const Node& b)//优先队列,从小到大
{
	return a.current_dist > b.current_dist;
}
  1. 判定结束条件,所有景点都走完时
  2. 当前距离已经大于最优值时,直接跳过该次循环,执行下一个景点的安排
if (current_node.current_dist >= best_distance)//不满足最优值时
			continue;
  1. 当前距离可能存在最优解时,将符合要求的各个景点依次放入队列中
  2. 重复步骤4到6的操作直到结束即可。

代码解析

#include
#include
#include 
#include 
using namespace std;
constexpr auto Max_size = 0x7fffffff;
double map[100][100];//邻接矩阵
double best_distance = Max_size;//当前最优路径长度
int Choiced[100];//记录当前最优路径
int vertex_count, edge_count;//景点个数,边数
struct Node {
	double current_dist;//当前已经走过的路径长度
	int id;//景点序号
	int Choiced[100];//当前路径序号
	Node() {}
	Node(double _current_dist, int _id) {//构造函数,便于参数传递
		current_dist = _current_dist;
		id = _id;
	}
};
int operator <(const Node& a, const Node& b)//优先队列,从小到大
{
	return a.current_dist > b.current_dist;
}
void bfs()
{
	memset(Choiced, 0, sizeof(Choiced));
	int current = 0;
	Node current_node, new_node;
	priority_queue<Node> q;//创建队列
	new_node = Node{ 0,2 };
	for (int i = 1; i <= vertex_count; i++)//初始化
		new_node.Choiced[i] = i;
	q.push(new_node);//压入一个初始节点
	while (!q.empty())//队列不为空时
	{
		current_node = q.top();//取出队头元素
		q.pop();//队头元素出队
		current = current_node.id;//物品序号
		if (current == vertex_count) {//最后一个景点时
			if (map[current_node.Choiced[current - 1]][current_node.Choiced[vertex_count]] != Max_size && map[current_node.Choiced[current]][1] != Max_size) {
				if (current_node.current_dist + map[current_node.Choiced[current - 1]][current_node.Choiced[vertex_count]] + map[current_node.Choiced[current]][1] < best_distance) {
					best_distance = current_node.current_dist + map[current_node.Choiced[current - 1]][current_node.Choiced[vertex_count]] + map[current_node.Choiced[current]][1];
					for (int i = 1; i <= vertex_count; i++)
						Choiced[i] = current_node.Choiced[i];
				}
			}
			continue;
		}
		else if (current_node.current_dist >= best_distance)//大于最优值
			continue;
		for (int j = current; j <= vertex_count; j++)
		{
			if (map[current_node.Choiced[j]][current_node.Choiced[current - 1]] != Max_size)
			{
				double dist = current_node.current_dist + map[current_node.Choiced[j]][current_node.Choiced[current - 1]];
				if (dist < best_distance) {
					new_node = { dist,current + 1 };
					for (int i = 1; i <= vertex_count; i++)
						new_node.Choiced[i] = current_node.Choiced[i];
					swap(new_node.Choiced[current], new_node.Choiced[j]);
					q.push(new_node);
				}
			}
		}
	}
	return;
}
int main()
{
	int v, w, dist;
	cout << "请输入景点个数:";
	cin >> vertex_count;
	cout << "请输入路线条数:";
	cin >> edge_count;
	cout << "请输入各景点之间的连接关系(v,w,dist):" << endl;
	for (v = 1; v <= vertex_count; v++)
		for (w = 1; w <= vertex_count; w++)
			map[v][w] = Max_size;
	for (int i = 1; i <= edge_count; i++) {
		cin >> v >> w >> dist;
		map[v][w] = map[w][v] = dist;
	}
	bfs();
	cout << "旅行的最短距离是:" << best_distance << endl;
	cout << "选择方案是: ";
	for (int i = 1; i <= vertex_count; i++)
		cout << Choiced[i] << "-->";
	cout << "1" << endl;
	return 0;
}
/*
1 2 15
1 3 30
1 4 5
2 3 6
2 4 12
3 4 3
*/

运行结果

分支界限算法--旅行商问题2_第1张图片


参考

实现有所参考《趣学算法》

你可能感兴趣的:(数据结构,#,算法题,#,exercise)