题意:
给定一系列按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
", 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
", dist[0][1] + dp[1][0]);
}
return 0;
}
貌似叫双调旅行商问题?