最小环+欧拉回路=最短哈密顿图
介绍
TSP(Traveling Salesman Problem)即旅行商问题,是数学领域中著名问题之一。这个问题是这样的:假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径长度为所有路径之中的最小值。TSP是一个典型的组合优化问题,且是一个NP完全难题,关于NP的这个概念本文就不做详细介绍了,但简单的说就是:TSP问题目前尚不能找到一个多项式时间复杂度的算法来求解。
n个城市 第一次选择n-1个城市,第二次n-2... 即要遍历n!次,普通遍历复杂度太高
算法
所以TSP旅行商问题有以下4种算法
- 贪心算法
- 模拟退火算法
- 遗传算法
- 基本蚁群算法
https://blog.csdn.net/wordsin/article/details/79915328
双调欧几里得旅行商问题
这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点。事实上,存在确定的最优双调路线的O(n*n)时间的算法。
是对平面上给定的n个点确定一条连接各点的最短闭合旅程的问题。 题目描述 现在笛卡尔平面上有n(n<=1000)个点,每个点的坐标为(x,y)(-2^31<x,y<2^31,且为整数),任意两点之间相互到达的代价为这两点的欧几里德距离 输入格式 第一行一个整数n 接下来n行,每行两个整数x,y,表示某个点的坐标。 输入中保证没有重复的两点, 保证最西端和最东端都只有一个点。 输出格式 一行,即最短回路的长度,保留2位小数。
思路
(1)首先将各点按照x坐标从小到大排列,时间复杂度为O(nlgn)。 (2)寻找子结构:定义从Pi到Pj的路径为:从Pi开始,从右到左一直到P1,然后从左到右一直到Pj。在这个路径上,会经过P1到Pmax(i,j)之间的所有点且只经过一次。
模板
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define INF 1e30 //数据上限
using namespace std;
const int MAX = 1000;//点的最大数
int n;double dis[MAX][MAX],dp[MAX][MAX];
struct node{
double x,y;
}a[MAX];
bool cmp(node a,node b) {
return a.x < b.x;
}
double Euc(node a,node b){//计算欧几里得距离
return sqrt(pow(a.x - b.x,2) + pow(a.y - b.y,2));
}
double DP(){
sort(a,a + n,cmp);//排序
for(int i = 0;i < n;i++){
for(int j = i + 1;j < n;j++){
dis[i][j] = Euc(a[i],a[j]);
dp[i][j] = INF;
}
}
dp[0][1] = dis[0][1];
for(int i = 0;i < n;i++){
for(int j = i + 1;j < n;j++){
dp[i][j + 1] = min(dp[i][j + 1],dp[i][j] + dis[j][j + 1]);
dp[j][j + 1] = min(dp[j][j + 1],dp[i][j] + dis[i][j + 1]);
}
}
double ans=INF;
for(int i = 0;i < n - 1;i++) ans = min(ans,dp[i][n - 1] + dis[i][n - 1]);
return ans;
}
int main(){
scanf("%d",&n);
for(int i = 0;i < n;i++)
scanf("%lf%lf",&a[i].x,&a[i].y);
double ans=DP();
printf("%0.2lf\n",ans);
return 0;
}
例题
来源:oschina
链接:https://my.oschina.net/u/4260070/blog/3432980