目录:
题目:
由于每个点要么在去的路上,要么在回来的路上,所以用二进制数表示N个点的状态,对于特殊的四个点特判一下,然后从所有状态中取最优的
期望得分:20分
考虑到每个点只能走一次,且从终点往回走和从起点再走一遍到终点没有区别,所以这道题可以转化为求两条不相交路径和的最小值。
于是考虑用动态规划求解。
用
F[i][j]
F
[
i
]
[
j
]
表示第一个点走到i,第二个点(回去的那个点)走到j的最优值。
为了保证更新时不会更新出
F[i][i]
F
[
i
]
[
i
]
(即一个点走了两次),而且每个点都会在路径上,我们每次用
F[i][j]
F
[
i
]
[
j
]
去更新点
max(i,j)+1
m
a
x
(
i
,
j
)
+
1
,所以转移方程为:
F[0][0]=0,k=max(i,j)+1
F
[
0
]
[
0
]
=
0
,
k
=
m
a
x
(
i
,
j
)
+
1
F[k][j]=max{F[k][j],F[i][j]+Dis(i,k)};
F
[
k
]
[
j
]
=
m
a
x
{
F
[
k
]
[
j
]
,
F
[
i
]
[
j
]
+
D
i
s
(
i
,
k
)
}
;
F[i][k]=max{F[i][k],F[i][j]+Dis(j,k)};
F
[
i
]
[
k
]
=
m
a
x
{
F
[
i
]
[
k
]
,
F
[
i
]
[
j
]
+
D
i
s
(
j
,
k
)
}
;
Dis(i,j)
D
i
s
(
i
,
j
)
为从i直接走到j点的距离.
对于两个特殊点和
max{i,j}=n
m
a
x
{
i
,
j
}
=
n
的情况特判处理即可。
期望得分:100
同时上面的DP也可以用记忆化搜索实现,对于
abs(x−y)>1
a
b
s
(
x
−
y
)
>
1
的情况,说明当前情况只能从
max{x,y}−1
m
a
x
{
x
,
y
}
−
1
转移过来,当
abs(x−y)=1
a
b
s
(
x
−
y
)
=
1
时,则能从
1 min{x,y}
1
m
i
n
{
x
,
y
}
中的任意一点转移过来,于是用记忆化搜索完成上面的步骤,加上适当剪枝即可。
期望得分:60~100分
代码:
#pragma GCC optimize("3")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int x[1001],y[1001];
double f[1001][1001],t[1001][1001];
int main()
{
/* freopen("path.in","r",stdin);
freopen("path.out","w",stdout);*/
int n=read(),b1=read()+1,b2=read()+1;
for(int i=1;i<=n;i++)
x[i]=read(),y[i]=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j) continue;
t[j][i]=t[i][j]=(double)sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=99999999;
f[1][1]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int k=max(i,j)+1;
if(k==n+1)
{
if(i==n) f[n][n]=min(f[n][n],f[i][j]+t[j][n]);
else f[n][n]=min(f[n][n],f[i][j]+t[i][n]);
continue;
}
if(k!=b1) f[i][k]=min(f[i][k],f[i][j]+t[j][k]);
if(k!=b2) f[k][j]=min(f[k][j],f[i][j]+t[i][k]);
}
printf("%.2lf",f[n][n]);
fclose(stdin);
fclose(stdout);
return 0;
}