双调欧几里得
参考 http://blog.sina.com.cn/s/blog_51cea4040100gkcq.html
二、
对所有的坐标按x递增排序,上图有7个点
假设d(i,j)是i点和j点的直线距离,p(i,j)是从i点到j点的最短双调欧几里得距离,那么我们可以得到p(i,j)=p(j,i),下面就i>=j的情况考虑,,假设点是1,2,....N
1. i==j 此时p(i,i)=p(i-1,i)+d(i-1,i)
2.j==i-1,此时在j之前有[1,j-1]个点, p(i,j)=min( p(j,k) +d(k,i) ),其中k>=1 && k<=j-1
3. j<i-1, 此时 p(i,j)=p(i-1,j)+d(i-1,i)
代码如下
#include<iostream> #include<cmath> #include<climits> #include<iomanip> using namespace std; typedef struct xy{ int x,y; }Point; #define N 7 void dp() { int i,j; Point* data=new Point[N+1]; for(i=1;i<=N;i++) cin>>data[i].x>>data[i].y; double p[N+1][N+1]={0}; double d[N+1][N+1]={0}; for(i=1;i<=N;i++) for(j=1;j<=N;j++) d[i][j]=sqrt((data[i].x-data[j].x)*(data[i].x-data[j].x)+(data[i].y-data[j].y)*(data[i].y-data[j].y)); p[1][2]=p[2][1]=sqrt((data[2].x-data[1].x)*(data[2].x-data[1].x)+(data[2].y-data[1].y)*(data[2].y-data[1].y)); p[1][1]=0; for(i=2;i<=N;i++) { // i=j+1 if(i==2) p[2][1]=p[1][2]=sqrt((data[2].x-data[1].x)*(data[2].x-data[1].x)+(data[2].y-data[1].y)*(data[2].y-data[1].y)); else p[i][i-1]=INT_MAX; for(j=1;j<=i-2;j++) { double temp=p[i-1][j]+d[i][j]; if(temp<p[i][i-1]) p[i][i-1]=p[i-1][i]=temp; } //i>j+3 for(j=1;j<=i-2;j++) { p[i][j]=p[i-1][j]+d[i][i-1]; p[j][i]=p[i][j]; } //i==j p[i][i]=p[i][i-1]+d[i][i-1]; } /* for(i=1;i<=N;i++) { for(j=1;j<=N;j++) cout<<fixed<<cout.precision(2)<<p[i][j]<<" "; cout<<endl; } */ cout<<fixed<<p[7][7]<<endl; delete [] data; } int main() { dp(); return 0; }
测试数据
1 1
2 7
3 4
6 3
7 6
8 2
9 5
结果 25.584025