点击打开链接
3 1 1 2 3 3 1
6.47 Hint: The way 1 - 3 - 2 - 1 makes the shortest path.题意:给N个二维平面上面的点,要从第一个点走到第N个点(若从i到j,必须i<j),再从第N个点走回第一个点(若从i到j,必须i>j),每个点只能访问且必须访问一次,求最短路径。我们把从第一个点到第N个点的路径看成路径0,第N个点到第一个点的路径看成路径1,那么除开第一个点和第N个点,其余每个点只有两种策略,要么在路径0,要么在路径1。我们从第N个点开始选,依次选点N-1,N-2.....1,这样定义状态 dp[i][x][y],表示n到i已经选过,路径0以x结束,路径1以y结束的最短路径(除开第N个点其余点只能在一条路径上),显然x和y其中一个一定是i,所以可以将空间优化到两维,dp[i][0][j]表示i在路径0,路径1以j结束的最短路径,dp[i][1][j]则表示i在路径1,路径0以i结束的最短路径。很容易写出转移方程:dp[i][0][j]=max(dp[i][0][j],dp[i+1][0][j]+dis(i+1,i)),i+1<=j<=n;dp[i][0][i+1]=max(dp[i][0][i+1],dp[i+1][1][j]+dis(i,j)),i+1<=j<=n;同理可得dp[i][1][j],dp[i][1][j+1]的转移方程,具体代码如下:#include<stdio.h> #include<iostream> #include<string> #include<string.h> #include<vector> #include<algorithm> #include<queue> #include<stack> #include<math.h> #define nn 110 #define inff 0x3fffffff #define mod 1000000007 #define eps 1e-9 using namespace std; typedef long long LL; struct node { int x,y; }a[2*nn]; int n; double dp[2*nn][2][2*nn]; double dis(int i,int j) { double f1=(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y); return sqrt(f1); } int main() { int i,j,k; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) { scanf("%d%d",&a[i].x,&a[i].y); } for(i=1;i<=n;i++) { for(j=0;j<=1;j++) { for(k=1;k<=n;k++) { dp[i][j][k]=1e20; } } } dp[n][0][n]=0; dp[n][1][n]=0; for(i=n-1;i>=0;i--) { for(j=i+1;j<=n;j++) { dp[i][0][j]=min(dp[i][0][j],dp[i+1][0][j]+dis(i,i+1)); dp[i][1][j]=min(dp[i][1][j],dp[i+1][1][j]+dis(i,i+1)); } for(j=i+1;j<=n;j++) { dp[i][0][i+1]=min(dp[i][0][i+1],dp[i+1][1][j]+dis(i,j)); dp[i][1][i+1]=min(dp[i][1][i+1],dp[i+1][0][j]+dis(i,j)); } } double ans=1e20; for(i=1;i<=n;i++) { ans=min(ans,dp[1][0][i]+dis(1,i)); ans=min(ans,dp[1][1][i]+dis(1,i)); } printf("%.2lf\n",ans); } return 0; }