题目链接:City Brain
显然两条路径之间,相交的部分一定是一段连续的路径。
所以我们可以枚举连续的路径,然后剩下4段不连续的路径。我们可以预处理两点之间的最短路,然后算出分别的和,然后三分即可。但是复杂度是 n * n * log 的。
但是我们可以发现,对于枚举连续的相同长度的路径我们只需要知道4段不连续路径的最小值,然后复杂度就变成 n * n + n * log 了。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=5010;
int n,m,k,d[N][N],mi[N],s1,t1,s2,t2; double res=1e18;
vector<int> g[N];
void bfs(int s){
queue<int> q; d[s][s]=0; q.push(s);
while(q.size()){
int u=q.front(); q.pop();
for(int to:g[u]) if(d[s][to]==-1) d[s][to]=d[s][u]+1,q.push(to);
}
}
double get(int x,int y){
if(!x) return 0.0;
return 1.0/(1+y/x)*(x-y%x)+1.0/(2+y/x)*(y%x);
}
double calc(int x,int y){
int l=0,r=k;
while(r-l>10){
int midl=l+(r-l)/3,midr=r-(r-l)/3;
if(2*get(x,midl)+get(y,k-midl)<=2*get(x,midr)+get(y,k-midr)) r=midr;
else l=midl;
}
double res=1e18;
for(int i=l;i<=r;i++) res=min(res,2*get(x,i)+get(y,k-i));
return res;
}
signed main(){
cin>>n>>m>>k; memset(d,-1,sizeof d); memset(mi,0x3f,sizeof mi);
for(int i=1,a,b;i<=m;i++) cin>>a>>b,g[a].push_back(b),g[b].push_back(a);
cin>>s1>>t1>>s2>>t2;
for(int i=1;i<=n;i++) bfs(i);
for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(d[i][j]!=-1){
int mi1=1e9,mi2=1e9;
if(d[s1][i]!=-1&&d[j][t1]!=-1) mi1=min(mi1,d[s1][i]+d[j][t1]);
if(d[t1][i]!=-1&&d[j][s1]!=-1) mi1=min(mi1,d[t1][i]+d[j][s1]);
if(d[s2][i]!=-1&&d[j][t2]!=-1) mi2=min(mi2,d[s2][i]+d[j][t2]);
if(d[t2][i]!=-1&&d[j][s2]!=-1) mi2=min(mi2,d[t2][i]+d[j][s2]);
if(mi1>=1e9||mi2>=1e9) continue;
mi[d[i][j]]=min(mi[d[i][j]],mi1+mi2);
}
for(int i=0;i<=n;i++) if(mi[i]<0x3f3f3f3f) res=min(res,calc(i,mi[i]));
printf("%.10lf\n",min(res,calc(0.0,d[s1][t1]+d[s2][t2])));
return 0;
}