经典动态规划问题:双调欧几里得旅行商问题
j < i - 1时,d[i][j] = d[i-1][j] + dis(i-1,i)
j = i-1时,d[i][j] = d[i][i-1] = min(d[i][i-1],d[k][j]+dis(i,k))
dp[n][n]=dp[n-1][n]+dist(n-1,n)
/*
经典动态规划问题:双调欧几里得旅行商问题
题意:给定平面n个点作为输入,希望你可以从最左端走到最右端,
然后再返回到最左端,就是一个回路。要求经过所有点的最短回路
j < i - 1时,d[i][j] = d[i-1][j] + dis(i-1,i)
j = i-1时,d[i][j] = d[i][i-1] = min(d[i][i-1],d[k][j]+dis(i,k))
dp[n][n]=dp[n-1][n]+dist(n-1,n)
*/
#include
#include
#include
#include
using namespace std;
const int N = 1005;
const double INF = 0x3f3f3f3f*1.0;
struct point
{
double x,y;
}p[N];
double d[N][N];//从i到最左端,再到j的最短路径
double dist(int i,int j)
{
return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(d,0,sizeof(d));
for(int i = 1;i <= n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
//计算所有情况下的b[i][j]
d[1][2] = dist(1,2);
for(int i = 3;i <= n;i++)
{
//j < i - 1时,d[i][j] = d[i-1][j] + dis(i-1,i)
for(int j = 1;j <= i-2;j++)
d[j][i] = d[j][i-1] + dist(i-1,i);
//j = i-1时,d[i][j] = d[i][i-1] = min(d[i][i-1],d[k][j]+dis(i,k))
d[i-1][i] = INF;
for(int j = 1;j <= i-2;j++)
{
if(d[j][i-1] + dist(j,i) < d[i-1][i])
d[i-1][i] = d[j][i-1] + dist(j,i);
}
}
d[n][n] = d[n-1][n] + dist(n-1,n);
printf("%.2f\n",d[n][n]);
}
return 0;
}