大体题意:
给你n 个点 已经按照x坐标排了序,问从左边的点一条线的走到右边的点并且一条线的返回起点,除了起点和终点外其余的点各走一次!
思路:
令dp[i][j]表示1~ max(i,j)都走过了,并且第一个人在i位置,第二个人在j位置,假设i > j。
那么1,2,3,,,,i位置都是走过的,第一个人可以走到i + 1,第二个人不动, 或者第二个人走到i+1,第一个人不动。
那么转移方程可以是:dp[i][j] = min(dist[i+1][i] + dp[i+1][j], dist[i+1][j] + dp[i+1][i]);
第一部分 dist[i+1][i] + dp[i+1][j] 的意思是 第二个人从j 走到 i+1,所以dp[i][j] = j到i+1的距离加上dp[i+1][i],因为始终保持i > j !
第二部分意思是 第一个人从i位置走到了i + 1位置 所以dp[i][j] 等于 i到i+1的距离加上 dp[i+1][j]。
这样最后还有一个边界问题,当i = n-1时, 表示1~n-1全部走过了 ,只剩下最后一段路了。所以dp[i][j]等于两个路程相加: dist[n-1][n] + dp[j][n];
因为是i = n-1时情况是知道的!
所以枚举i 要从后往前枚举,j的枚举无所谓了,从前到后 从后到前都可以!!
最后答案就是 dp[2][1] + dist[2][1],画一个图就可以看出 第一个在2位置,第二个在1位置,他们走完后只剩下了1到2这一段路程,加上即可!
详细见代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1000 + 10;
struct Node{
int x,y;
void get(int x_,int y_){
x = x_; y = y_;
}
double dis(const Node & rhs){
return sqrt((rhs.y-y)*(rhs.y-y) + (rhs.x-x) * (rhs.x-x));
}
}p[maxn];
double dist[maxn][maxn];
double dp[maxn][maxn];
int main(){
int n;
while(scanf("%d",&n) == 1){
memset(dp,0,sizeof dp);
for (int i = 1; i <= n; ++i){
int x,y;
scanf("%d%d",&x,&y);
p[i].get(x,y);
}
for (int i = 1; i <= n; ++i){
for (int j = 1; j <= n; ++j){
dist[i][j] = p[i].dis(p[j]);
}
}
for (int i = n-1; i >= 1; --i){
for (int j = i-1; j >= 1; --j){
if (i == n-1)dp[i][j] = dist[n-1][n] + dist[j][n];
else dp[i][j] = min(dist[i+1][j] + dp[i+1][i] , dist[i+1][i] + dp[i+1][j]);
}
}
printf("%.2lf\n",dp[2][1] + dist[2][1]);
}
return 0;
}
=================
复习的代码:
2016.9.28
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1000 + 7;
struct Node{
double x,y;
void read(){
scanf("%lf %lf",&x, &y);
}
}p[maxn];
double dp[maxn][maxn];
double dist[maxn][maxn];
int main(){
int n;
while(scanf("%d",&n) == 1){
for (int i = 1; i <= n; ++i){
p[i].read();
}
for (int i = 1; i <= n; ++i){
dist[i][i] = 0;
for (int j = i+1; j <= n; ++j){
dist[i][j] = dist[j][i] = sqrt((p[j].x-p[i].x) * (p[j].x-p[i].x) + (p[j].y-p[i].y) * (p[j].y-p[i].y));
}
}
for (int i = 1; i < n-1; ++i){
dp[n-1][i] = dist[n-1][n] + dist[i][n];
}
for (int i = n-2;i >= 1; --i){
for (int j = i-1; j >= 1; --j){
dp[i][j] = min(dp[i+1][i] + dist[j][i+1],dp[i+1][j] + dist[i][i+1]);
}
}
printf("%.2f\n",dp[2][1] + dist[1][2]);
}
return 0;
}