背景
欧几里德旅行商(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
理解错题意,以为两条路长度不等,结果就不会做了
结果根本没有这个要求,那么就是单纯的找到一个环,长度最小,环上的点包含全部的点并且每个点只出现一次
有点像借教室那道题
我们可以思考一下,实际上所有的点最后被分成了两部分
那么就可以做DP
f[i][j]表示第一条路走到了i点,第二条路做到了j点,1~j之间的点全部被经过了
那么我们用这个状态更新其他状态,发现下一步只有两种可能,一个是第一条路从i走到了j+1,一个是第二条路从j走到了j+1
然后就好了
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 #define inf 1e30 3 #define maxn 1000+5 4 #define maxm 5000000+5 5 #define eps 1e-10 6 #define ll long long 7 #define mod 5000011 8 #define for0(i,n) for(int i=0;i<=(n);i++) 9 #define for1(i,n) for(int i=1;i<=(n);i++) 10 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 11 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 12 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 13 using namespace std; 14 int read(){ 15 int x=0,f=1;char ch=getchar(); 16 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 17 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 struct poi{ 21 int x,y; 22 }a[maxn]; 23 int n; 24 double f[maxn][maxn]; 25 double cal(int i,int j){ 26 double t1=a[i].x-a[j].x,t2=a[i].y-a[j].y; 27 return sqrt(t1*t1+t2*t2); 28 } 29 bool cmp(poi a,poi b){ 30 return a.x<b.x; 31 } 32 int main(){ 33 //freopen("input.txt","r",stdin); 34 //freopen("output.txt","w",stdout); 35 n=read(); 36 for1(i,n) 37 for2(j,i+1,n) 38 f[i][j]=inf; 39 for1(i,n){ 40 a[i].x=read();a[i].y=read(); 41 } 42 sort(a+1,a+n+1,cmp); 43 f[1][2]=cal(1,2); 44 for1(i,n) 45 for(int j=i+1;j<=n;j++){ 46 f[i][j+1]=min(f[i][j+1],f[i][j]+cal(j,j+1)); 47 f[j][j+1]=min(f[j][j+1],f[i][j]+cal(i,j+1)); 48 } 49 double ans=inf; 50 for1(i,n-1) 51 ans=min(ans,f[i][n]+cal(i,n)); 52 printf("%.2lf",ans); 53 return 0; 54 }