UVA 1347_Tour

题意:

给定一系列按x坐标升序排列的点,一个人从左向右走到终点再从终点走回起点,要求每个点恰好经过一次,问所走过的最短路径长度。

分析:

可以看成是两个人同时从起点向终点走,且除起点终点外每个点恰有一个人经过。

John uses the following strategy: he starts from the leftmost point, then he goes strictly left to right to the rightmost point, and then he goes strictly right back to the starting point.

用d[i][j]表示一个人走到第i个位置,另一个人走到第j个位置时,已经共走了多少距离,规定其中i>j,且1~i全部走过。
题目要求严格按照从左到右和从右到左的顺序,所以不管哪个人下一步只能走i+1,i+2….如果一个人跳过i+1直接走到了i+2,则i+1必将由另一个人走,不妨让走i+1的人先走,这样便保证每次都先走到i+1,得到状态转移方程:(dist数组保存两点之间距离)

dp[i+1][j]=min(dp[i+1][j],dp[i][j]+dist[i+1][i]);
dp[i+1][i]=min(dp[i+1][i],dp[i][j]+dist[i+1][j]);

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=55, INF = 0x3fffffff; //为什么是55?
double x[maxn],y[maxn],dist[maxn][maxn],dp[maxn][maxn];
int main(void)
{
 int n;
 while(scanf("%d",&n) == 1){
 for(int i =0; i < n ; i++)
 scanf("%lf%lf",&x[i], &y[i]);
 for(int i = 0;i < n; i++)
 for(int j = 0 ; j < n ; j++)
 dist[i][j] = sqrt((x[i] - x[j]) * (x[i]-x[j]) + (y[i] - y[j]) * (y[i] - y[j]));

 for(int i = 0; i < n; i++){
 for(int j = 0; j < n; j++)
 dp[i][j] = INF;
 }
 dp[1][0]=dist[1][0];

 for(int i = 1; i < n - 1; i++) {
 for(int j = 0; j < i; j++){
 dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + dist[i + 1][i]);
 dp[i + 1][i] = min(dp[i + 1][i], dp[i][j] + dist[i + 1][j]);
 }
 }

 double ans = INF;
 for(int i = 0; i < n - 1; i++){
 ans = min(ans, dp[n-1][i] + dist[n - 1][i]);

 }
 printf("%.2lf\n", ans);
 }
 return 0;
}

还可以用d[i][j]表示一个人走到第i个位置,另一个人走到第j个位置时,还剩多少距离,则状态转移方程

dp[i][j]=min(dist[i][i+1]+dp[i+1][j],dist[j][i+1]+dp[i+1][i]);  

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=55, INF = 0x3fffffff; //为什么是55?
double x[maxn],y[maxn],dist[maxn][maxn],dp[maxn][maxn];
int main(void)
{
 int n;
 while(scanf("%d",&n) == 1){
 for(int i =0; i < n ; i++)
 scanf("%lf%lf",&x[i],&y[i]);
 for(int i = 0;i < n; i++)
 for(int j = 0 ; j < n ; j++)
 dist[i][j] = sqrt((x[i] - x[j]) * (x[i]-x[j]) + (y[i] - y[j]) * (y[i] - y[j]));

 for(int i = n - 2; i >=1; i--) {
 for(int j = i - 1; j >= 0; j--){
 if(i == n - 2) dp[i][j] = dist[i][n - 1] + dist[j][n - 1];
 else
 dp[i][j] = min(dist[i][i + 1]+dp[i + 1][j], dist[j][i + 1] + dp[i + 1][i]);
 }
 }
 printf("%.2lf\n", dist[0][1] + dp[1][0]);
 }
 return 0;
}

貌似叫双调旅行商问题?

你可能感兴趣的:(uva)