双调欧几里得
参考 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
浙公网安备 33010602011771号