Tour
给定平面上n(n<=1000)个点的坐标(按照x递增的顺序给出。各点x坐标不同,且均为整数),你的任务是设计一条路线,从最左边的点出发走到最右边的点再返回,要求除了最左边和最右边之外,每个点恰好经过一次,且路径总长度最短,两点间的长度为它们的欧几里得距离。
状态定义:dp(i,j)表示1~max(i,j)全部走过,且两个人的当前位置分别是i和j,还需要走多长的距离 。
不难发现dp(i,j)=dp(j,i),因此从现在开始规定在状态中i>j。这样,不管是那个人,下一步只能走到i+1,i+2,…这些点。可是,如果走到i+2,情况变成了“1~i和i+2,但是i+1没走过”,无法表示成状态!怎么办?禁止这样的决策!也就是说,只允许其中一个人走到i+1,而不能走到i+2,i+3,…。
换句话说,状态dp(i,j)只能转移到dp(i+1,j)或者dp(i,i+1)(由于i>j,而dp(i,j)=dp(j,i)),所以 状态dp(i,j)只能转移到dp(i+1,j)或者dp(i+1,i) 。
边界条件 :dp(n-1,j)=dist(n-1,n)+dist(j,n)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int n;
struct node {
double x,y;
} a[1005];
double dp[1005][1005];
double dist(int i,int j) {
return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
//dp(i,j)表示1~max(i,j)全部走过,且两个人的当前位置分别是i和j,还需要走多长的距离 。
//dp[i][j]=dp[j][i]
double solve(int i,int j) {//记忆化搜索时保证i>j
if(dp[i][j]>0)
return dp[i][j];
return dp[i][j] = min(solve(i+1,j)+dist(i,i+1),solve(i+1,i)+ dist(j,i+1));
}
int main() {
double ans;
while(cin>>n) {
for(int i=1; i<=n; i++) {
cin>>a[i].x>>a[i].y;
}
memset(dp,0,sizeof(dp));
for(int i=1; i<n-1; i++) {
dp[n-1][i]=dist(n-1,n)+dist(i,n);
}
ans=solve(1,1);
printf("%.2f\n",ans);
}
return 0;
}