JZOJ 3510. 【NOIP2013模擬11.5B組】最短路徑
阿新 • • 發佈:2019-01-29
目錄:
題目:
由於每個點要麼在去的路上,要麼在回來的路上,所以用二進位制數表示N個點的狀態,對於特殊的四個點特判一下,然後從所有狀態中取最優的
期望得分:20分
考慮到每個點只能走一次,且從終點往回走和從起點再走一遍到終點沒有區別,所以這道題可以轉化為求兩條不相交路徑和的最小值。
於是考慮用動態規劃求解。
用表示第一個點走到i,第二個點(回去的那個點)走到j的最優值。
為了保證更新時不會更新出(即一個點走了兩次),而且每個點都會在路徑上,我們每次用 去更新點,所以轉移方程為:
為從i直接走到j點的距離.
對於兩個特殊點和 的情況特判處理即可。
期望得分:100
同時上面的DP也可以用記憶化搜尋實現,對於的情況,說明當前情況只能從轉移過來,當時,則能從中的任意一點轉移過來,於是用記憶化搜尋完成上面的步驟,加上適當剪枝即可。
期望得分: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;
}