背景
欧几里德旅行商(Euclidean Traveling Salesman)问题也就是货郎担问题一直是困扰全世界数学家、计算机学家的著名问题。现有的算法都没有办法在确定型机器上在多项式时间内求出最优解,但是有办法在多项式时间内求出一个较优解。
为了简化问题,而且保证能在多项式时间内求出最优解,J.L.Bentley提出了一种叫做bitonic tour的哈密尔顿环游。它的要求是任意两点(a,b)之间的相互到达的代价dist(a,b)=dist(b,a)且任意两点之间可以相互到达,并且环游的路线只能是从最西端单向到最东端,再单项返回最西端,并且是一个哈密尔顿回路。
描述
著名的NPC难题的简化版本
现在笛卡尔平面上有n(n<=1000)个点,每个点的坐标为(x,y)(-2^31<x,y<2^31,且为整数),任意两点之间相互到达的代价为这两点的欧几里德距离,现要你编程求出最短bitonic tour。
格式
输入格式
第一行一个整数n
接下来n行,每行两个整数x,y,表示某个点的坐标。
输入中保证没有重复的两点,
保证最西端和最东端都只有一个点。
输出格式
一行,即最短回路的长度,保留2位小数。
样例1
样例输入1
7
0 6
1 0
2 3
5 4
6 1
7 5
8 2
样例输出1
25.58
限制
1s
来源
《算法导论(第二版)》 15-1
1 #include <iostream> 2 #include <string.h> 3 #include <cstdio> 4 #include <stdlib.h> 5 #include <algorithm> 6 #include <math.h> 7 8 using namespace std; 9 struct area 10 { 11 int x,y;//坐标 (x,y) 12 }; 13 14 double f[1002][1002],dis[1002][1002]; 15 const double INF=1e30; 16 double ans=INF; 17 18 bool comp(const area &q,const area &w) 19 { 20 return q.x<w.x; 21 } 22 23 int main() 24 { 25 int n; 26 cin>>n; 27 area poi[1002]; 28 for(int i=1;i<=n;i++) 29 cin>>poi[i].x>>poi[i].y; 30 sort(poi+1,poi+n+1,comp); 31 for(int i=1;i<=n-1;i++) 32 for(int j=i+1;j<=n;j++) 33 { 34 int x1=poi[i].x,x2=poi[j].x,y1=poi[i].y,y2=poi[j].y; 35 dis[i][j]=sqrt(fabs(x1-x2)*fabs(x1-x2)+fabs(y1-y2)*fabs(y1-y2)); 36 f[i][j]=ans; 37 } 38 f[1][2]=dis[1][2]; 39 for(int i=1;i<=n;i++) 40 for(int j=i+1;j<=n;j++)//默认f数组前一个参数比后一个参数小 41 { 42 f[i][j+1]=min(f[i][j]+dis[j][j+1],f[i][j+1]); 43 f[j][j+1]=min(f[i][j]+dis[i][j+1],f[j][j+1]); 44 } 45 double min0=INF; 46 for(int i=1;i<=n-1;i++) 47 { 48 min0=min(f[i][n]+dis[i][n],min0); 49 } 50 printf("%.2f\n",min0); 51 return 0; 52 }
为了防止自己做题以后全部忘掉(而这显然是总是这样) 今天开始较难的题目都要写简单的思路
首先是wa点:
被这个wa了两次呢:)
思路:
首先将所有点以x由小到大排序编号
很容易想到:所有的点,除了首尾都会被分为两份,为了便于解出就将这两份看做是两个人行走的不同轨迹,某点不是在甲走的路上就是在乙走的路上
便于记录,事先规定f[][]前面一个参数要比后一个小
初始化i到j的距离数组dis[][](i<j,当然你i>j的时候也存也没事)
于是容易得出动规方程
f[i][j+1]=min(f[i][j]+dis[j][j+1],f[i][j+1]) (当本来在j点的人走到了j+1点)
f[i][j+1]=min(f[i][j]+dis[i][j+1],f[i][j+1]) (当本来在i点的人走到了j+1点)
这样就很简单了,接下来你最终能得到f所有第二个参数为n的值,然后找出其中的最小值就可以啦
end~