刘汝佳给这道题的分析真的妙。太大佬了。
1.“从左到右再回来”不太方便思考,可以改成:两个人同时从最左点出发,沿着两条不同
的路径走,最后都走到最右点,且除了起点和终点外其余每个点恰好被一个人经过。 这样,
就可以用d(i,j)表示第一个人走到i,第二个人走到j,还需要走多长的距离。
这样换个方式思考就大大减少了复杂度!
2.好像很难保证两个人不会走到相同的点。 例如,
计算状态d(i,j)时,能不能让i走到i+1呢?不知道,因为从状态里看不出来i+1有没有被j走
过。 换句话说,状态定义得不好,导致转移困难
计算状态d(i,j)时,能不能让i走到i+1呢?不知道,因为从状态里看不出来i+1有没有被j走
过。 换句话说,状态定义得不好,导致转移困难
3.下面修改一下:d(i,j)表示1~max(i,j)全部走过,且两个人的当前位置分别是i和j,还需
要走多长的距离。 不难发现d(i,j)=d(j,i),因此从现在开始规定在状态中i>j。 这样,不管是
哪个人,下一步只能走到i+ 1 , i+2,…这些点。 可是,如果走到i+2,情况变成了“1~i和i+
2,但是i+1没走过”,无法表示成状态!怎么办?禁止这样的决策!也就是说,只允许其中
一个人走到i+1,而不能走到i+2, i+3,…。 换句话说,状态d(i,j)只能转移到d(i+1,j)和d(i+
1,i)。
要走多长的距离。 不难发现d(i,j)=d(j,i),因此从现在开始规定在状态中i>j。 这样,不管是
哪个人,下一步只能走到i+ 1 , i+2,…这些点。 可是,如果走到i+2,情况变成了“1~i和i+
2,但是i+1没走过”,无法表示成状态!怎么办?禁止这样的决策!也就是说,只允许其中
一个人走到i+1,而不能走到i+2, i+3,…。 换句话说,状态d(i,j)只能转移到d(i+1,j)和d(i+
1,i)。
4.状态总数有O(n2)个,每个状态的决策只有两个,因此总时间复杂度为O(n2)。
这个状态转移:d(i,j)只能转移到d(i+1,j)和d(i+1,i)只适合递归记忆化搜索求解,因为我们不能事先知道
i+1的状态,我尝试过从后往前推,也是不可能的。(根据对称性也能想明白)。
如果写成循环递推的形式需要对状态转移方程进行修改,d(i, j)的得来应该分两种,j < i - 1 和j == i - 1时,
这两种递推需要分开写。d(i,j)= d(i - 1,j) + dist(i-1,i)和d(i,i-1)= min( d(i,i - 1),d(i - 1, j) + dist(j,i))
这两个式子看似互相独立,但是都影响着将来。
最后是dp的边界条件,初始肯定要有人走第一步,这个初始化一下。
第二个是i走到i后还要再让j走到最后一步。
#include <bits/stdc++.h>
using namespace std;
#define M 1010
typedef pair<int, int> P;
#define f first
#define s second
#define INF 100000000
P date[M];
double dp[M][M];
double ans;
//bool vis[M];
//distance
double dist(int i, int j)
{
double x = abs(date[i].f - date[j].f);
double y = abs(date[i].s - date[j].s);
return hypot(x, y);
}
int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
for(int i = 1; i <= n; i++){
scanf("%d%d", &date[i].f, &date[i].s);
}
for(int i = 0; i <= n; i++){
for(int j = 0; j <= n; j++){
dp[i][j] = INF;
}
}
// memset(vis, 0, sizeof(vis));
//edge
dp[2][1] = dist(2, 1);
ans = INF;
for(int i = 3; i <= n; i++){
for(int j = 1; j < i - 1; j++){
dp[i][j] = dp[i - 1][j] + dist(i, i - 1);
dp[i][i - 1] = min(dp[i][i - 1], dp[i - 1][j] + dist(j, i));
}
}
//j‘s last step
for(int i = 1; i < n; i++)
ans = min(ans, dp[n][i] + dist(n, i));
printf("%.2lf\n", ans);
}
return 0;
}