关于单向TSP旅行商问题/修路问题/最小生成树问题的求解讨论

旅行商问题,又称旅行者,推销员问题,货郎担问题。该问题十分经典,几十年前用于计算机国际竞赛,现在被用来作为算法的入门练习。 

假设有一个商人要拜访n个城市,他必须走完所有路径,且路径不能重复,并且走到最后能回到原来路径。

事实上我们可以将这个问题转换成一张图(丑了点)

注:这篇文章是对无向路径进行求解,并非双向,又称为修路问题以及最短路径问题。

该题只为TSP问题的一个特例,核心是——最小生成树问题

例如这样:

可以画出它的邻接矩阵:

类似这样:

 邻接矩阵中对应位置写出与自己相连的点距离值

 0代表当前旅行商的位置,那么问题就转换成了,我要如何走这张图,才能让我走完每个点,并且不能重复过点,而且使得最终路径最短

以上三个要求其实就是解决问题的入题点,无论使用动态规划还是蛮力法都只是对上面三个条件的求解。

 这样的题目我们通常采用的方法是将其转换成可以用数学方式解答的问题。

那么我们常用的手段就是图和树:

这道题是一个点——线问题,那么用图可以将问题抽象出来

我们将图一转换成一个邻接矩阵    邻接矩阵可以将点和边的关系很好的展现出来

 我们将点装进集合,走过一个点,就把它从集合中剔除,这样可以保证不走重复路径

将走过的路径装进一个数组中,每次走了一条路,就把路径与之前走过的路径相加。

 那么这个问题就可以分为三个步骤:

  1. 初始化点的集合和走过的路径长度
  2. 寻找最近的没走过的点
  3. 将这个点从集合中剔除,并将路径与原来路径相加,表示走过了这条路。

下面是C++的源代码

#include<iostream>
using namespace std;
const int INF = 0x3ffffffff;
const int N = 100;
bool s[N];
int closest[N];
int lowcost[N];
void Prim(int n, int u0, int c[N][N])
{
	//顶点个数,开始顶点,带权矩阵
	//如果s[i]=true,说明顶点i属于句话V-U
	//将最后的相关的最小权值传递到数组lowcost
	s[u0] = true;//最初时,集合中U只有一个元素,即顶点u0
	int i;
	int j;
	for (i = 1; i <= n; i++) {
		if (i != u0) {
			lowcost[i] = c[u0][i];
			closest[i] = u0;
			s[i] = false;
		}
		else {
			lowcost[i] = 0;
		}
		for (i = 1; i <= n; i++) {
			int temp = INF;
			int t = u0;
			for (j = 1; j <= n; j++) {
				if ((!s[j]) && (lowcost[j] < temp))
				{
					t = j;
					temp = lowcost[j];
				}
			}
			if (t == u0) {
				break;
			}
			s[t] = true;
			for (j = 1; j <= n; j++) {
				if ((!s[j]) && (c[t][j] < lowcost[j]))
				{
					lowcost[j] = c[t][j];
					closest[j] = t;
				}
			}
		}
	}
	
}
int main() {
	int n, c[N][N], m, u, v, w;
	int u0;
	cout << "输入结点数n和边数m:" << endl;
	cin >> n >> m;
	int sumcost = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			c[i][j] = INF;
		}
	}
	cout << "输入结点数u,v和边值w: " << endl;
	for (int i = 1; i <= m; i++) {
		cin >> u >> v >> w;
		c[u][v] = c[v][u] = w;
	}
	cout << "输入任一结点u0: " << endl;
	cin >> u0;
	Prim(n, u0, c);
	cout << "数组lowcost的内容为: " << endl;
	for (int i = 1; i <= n; i++) {
		cout << lowcost[i] << " ";
	}
	cout << endl;
	for (int i = 1; i <= n; i++) {
		sumcost += lowcost[i];
	}
	cout << "最小的花费是:" << sumcost << endl << endl;
	return 0;
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蚁群算法可以用来解决TSP问题,其基本思路是将蚂蚁的行走路径表示为待优化问题的可行解,整个蚂蚁群体的所有路径构成待优化问题的解空间。路径较短的蚂蚁释放的信息素量较多,随着时间的推移,较短的路径上累积的信息素浓度逐渐增高,选择该路径的蚂蚁数量也越来越多。最终,整个蚂蚁会在正反馈的作用下集中到最佳的路径上,此时对应的便是待优化问题的最优解。 蚁群算法解决TSP问题的基本步骤如下: 1. 初始化信息素和蚂蚁的位置。 2. 蚂蚁按照一定的策略选择下一个城市,并更新信息素。 3. 计算每只蚂蚁的路径长度,并记录最短路径。 4. 更新信息素,使得路径较短的蚂蚁释放的信息素量较多。 5. 重复步骤2-4,直到满足停止条件。 下面是一个Python实现的例子: ```python import numpy as np # 城市数量 num_cities = 10 # 蚂蚁数量 num_ants = 20 # 信息素重要程度 alpha = 1 # 启发式因子重要程度 beta = 5 # 信息素挥发速度 rho = 0.1 # 初始信息素浓度 tau0 = 1 # 最大迭代次数 max_iter = 100 # 城市坐标 cities = np.random.rand(num_cities, 2) # 计算城市之间的距离 distances = np.zeros((num_cities, num_cities)) for i in range(num_cities): for j in range(num_cities): distances[i][j] = np.sqrt((cities[i][0] - cities[j][0]) ** 2 + (cities[i][1] - cities[j][1]) ** 2) # 初始化信息素 pheromones = np.ones((num_cities, num_cities)) * tau0 # 迭代 for iter in range(max_iter): # 初始化蚂蚁位置 ants = np.zeros((num_ants, num_cities), dtype=int) for i in range(num_ants): ants[i][0] = np.random.randint(num_cities) # 蚂蚁选择下一个城市 for i in range(num_ants): for j in range(1, num_cities): # 计算城市之间的启发式信息 eta = 1.0 / distances[ants[i][j - 1]][:] # 计算城市之间的信息素浓度 tau = pheromones[ants[i][j - 1]][:] # 计算城市之间的转移概率 p = np.power(tau, alpha) * np.power(eta, beta) p[ants[i]] = 0 p = p / np.sum(p) # 选择下一个城市 ants[i][j] = np.random.choice(num_cities, p=p) # 计算每只蚂蚁的路径长度 lengths = np.zeros(num_ants) for i in range(num_ants): for j in range(num_cities - 1): lengths[i] += distances[ants[i][j]][ants[i][j + 1]] lengths[i] += distances[ants[i][num_cities - 1]][ants[i][0]] # 记录最短路径 best_ant = np.argmin(lengths) best_path = ants[best_ant] best_length = lengths[best_ant] # 更新信息素 pheromones *= (1 - rho) for i in range(num_ants): for j in range(num_cities - 1): pheromones[ants[i][j]][ants[i][j + 1]] += 1.0 / lengths[i] pheromones[ants[i][num_cities - 1]][ants[i][0]] += 1.0 / lengths[i] # 输出结果 print("最短路径:", best_path) print("最短路径长度:", best_length) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值