思路:
20分:
直接考虑用dfs暴搜完事
100分:
感性理解一下题目,从1~n再从 n1,转换一下就成了1n的两条不同路径之和最短的问题。
类似提高组2008年传纸条。
设f[i][j]为第一条路走到i号点,第二条路径走到第j号点的最短路径和。为了保证不出现两路相交的情况,即:f[i][i]。每次使用f[i][j]去更新max(i,j)+1,
所以动态转移方程为:
f
[
1
]
[
1
]
=
0
;
k
=
m
a
x
(
i
,
j
)
+
1
d
i
s
(
i
,
j
)
表
示
从
i
点
到
j
点
的
距
离
f[1][1] = 0; k = max(i, j) + 1 \;\;dis(i,j)表示从i点到j点的距离
f[1][1]=0;k=max(i,j)+1dis(i,j)表示从i点到j点的距离
f
[
k
]
[
j
]
=
m
a
x
(
f
[
k
]
[
j
]
,
f
[
i
]
[
j
]
+
d
i
s
(
i
,
k
)
)
f[k][j] = max(f[k][j], f[i][j] + dis(i,k))
f[k][j]=max(f[k][j],f[i][j]+dis(i,k))
f
[
i
]
[
k
]
=
m
a
x
(
f
[
i
]
[
k
]
,
f
[
i
]
[
j
]
+
d
i
s
(
j
,
k
)
)
f[i][k] = max(f[i][k], f[i][j] + dis(j, k))
f[i][k]=max(f[i][k],f[i][j]+dis(j,k))
对于b1,b2和k - 1 == n的情况,我们只需要将点强制转换到特殊点即上述三点上。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 1e3 + 10;
int n, b1, b2;
double f[N][N], x[N], y[N];
double d(int a, int b) {return sqrt((x[a] - x[b]) * (x[a] - x[b]) * 1.0 + (y[a] - y[b]) * (y[a] - y[b]) * 1.0);}
int main()
{
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
scanf("%d%d%d", &n, &b1, &b2);
for(int i = 1; i <= n; i++) scanf("%lf%lf", &x[i], &y[i]);
memset(f, 0x7f, sizeof(f));
f[1][1] = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(i == j && i != 1) continue;
int k = max(i, j) + 1;
if(k > n)
{
if(i < n) f[n][n] = min(f[n][n], f[i][j] + d(i, n));
if(j < n) f[n][n] = min(f[n][n], f[i][j] + d(j, n));
}
else
{
if(k != b2 + 1) f[k][j] = min(f[k][j], f[i][j] + d(i, k));
if(k != b1 + 1) f[i][k] = min(f[i][k], f[i][j] + d(j, k));
}
}
printf("%.2lf\n", f[n][n]);
return 0;
}