题意:
给出二维平面上的n个点,现在从最左端出发,到达最右端的点,再返回最左端的点,要求遍历所有点且路程最短。
思路:
这是一个双调欧几里得旅行商问题。双线程dp。
:快的人走到i,慢的人走到j的最短路程(i>j)。
对于当前点,要不在走得快的人走的边上,要不在走得慢的人走的边上。
有状态转移方程:
在走得快的人走的边上:
。
在走得慢的人走的边上:
。
代码:
struct point
{
int x,y;
}p[530];
double dp[530][530];
bool cmp(point a,point b)
{
return a.x<b.x;
}
double dis(point a,point b)
{
return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
scanf("%d%d",&p[i].x,&p[i].y);
sort(p,p+n,cmp);
memset(dp,0x7f,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;i++)
dp[i][0]=dp[i-1][0]+dis(p[i],p[i-1]);
for(int i=0;i<n;i++)
for(int j=0;j<i;j++)
{
dp[i+1][j]=min(dp[i+1][j],dp[i][j]+dis(p[i],p[i+1]));
dp[i+1][i]=min(dp[i+1][i],dp[i][j]+dis(p[j],p[i+1]));
}
double ans=1e18;
for(int i=0;i<n-1;i++)
ans=min(ans,dp[n-1][i]+dis(p[i],p[n-1]));
printf("%.2f\n",ans);
}
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!