题目描述
mifafa 正在编写杭州城市大脑智能引擎。
杭州的道路可以被抽象成为一幅无向图。每条路的初始速度都是 1 m / s 1 m / s 。 1\mathrm{m/s}1m/s。 1m/s1m/s。
mifafa 可以使用 1 RMB 1\texttt{RMB} 1RMB 让任意一条路的速度提升 1 m / s 1\mathrm{m/s} 1m/s。如果一条路的速度为 a m / s a\mathrm{m/s} am/s,那么我们需要 1 a s \frac{1}{a}\mathrm{s} a1s 才能通过这条道路。初始 mifafa 有 k RMB k\texttt{RMB} kRMB,mifafa 要把这 k RMB k\texttt{RMB} kRMB 花在升级这些道路上。
有两人的路线是s1-t1 s2-t2
,请问 mifafa 要怎么花钱,使得两位选手花费的总时间最少?当 mifafa 花完
RMB
\texttt{RMB}
RMB 之后,两位选手都会走花费时间最少的路。mifafa 花在每条道路上的钱都必须是非负整数。
0 ≤ n , m ≤ 5000 , 0 ≤ k ≤ 1 0 9 , 0 ≤ n , m ≤ 5000 , 0 ≤ k ≤ 1 0 9 0 \le n,m \le 5000,0 \le k \le 10^9,0≤n,m≤5000,0≤k≤10^9 0≤n,m≤5000,0≤k≤109,0≤n,m≤5000,0≤k≤109
性质1:两位选手走过的路如果有重合的地方,那么这一段必定是连续的
证明:假设他们中间的重复路段是隔开的,那么就可以直接让他们走一条共同的最短路,这样连着的就是一条连续的线段了
所以我们可以先预处理出两点之间的距离,然后枚举重复线段的两个端点,然后通过端点把整个图给连起来。
性质2:对于每个一样长度的重复路径,肯定选的是边上连的最小
然后就进行三分求单峰函数的值(需填坑)
#include<bits/stdc++.h>
#define maxn 5050
#define int long long
#define lb long double
using namespace std;
inline int read()
{
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
return res*f;
}
int n,m,k;
int head[maxn];
int dis[maxn][maxn];
struct node{
int to,next;
}edge[maxn*2];
int tot;
inline void add(int x,int y){
edge[++tot].to=y;
edge[tot].next=head[x];
head[x]=tot;
}
queue<int>q;
inline void bfs(int x)
{
dis[x][x]=0;
q.push(x);
while(!q.empty())
{
int now=q.front();q.pop();
for(int i=head[now];i;i=edge[i].next){
int to=edge[i].to;
if(dis[x][to]>dis[x][now]+1){
dis[x][to]=dis[x][now]+1;
q.push(to);
}
}
}
}
int s1,s2,t1,t2;
int x,y;
int Ans[maxn];
lb D[maxn*2];
int id[maxn];
lb num,ans=1e8;
inline lb cale(int a,int b,int x){lb ti=0;int y=k-x;int c=x/a+1,d=x%a;lb lbc=c,lbd=d;ti+=((lb)a)/(lbc)*2.0;ti-=lbd*(1.0/(lbc))*2.0;ti+=lbd*(1.0/(lbc+1.0))*2.0;c=y/b+1,d=y%b;lbc=c,lbd=d;ti+=((lb)b)/(lbc);ti-=lbd*(1.0/(lbc));ti+=lbd*(1.0/(lbc+1.0));return ti;}
signed main()
{
// freopen("city.in","r",stdin);freopen("city.out","w",stdout);
n=read();m=read();k=read();
for(int i=1;i<=m;i++)
{
int u,v;
u=read();v=read();
add(u,v);add(v,u);
}
memset(Ans,1e6,sizeof(Ans));
memset(dis,1e6,sizeof(dis));
for(int i=1;i<=n;i++)bfs(i);
s1=read();t1=read();s2=read();t2=read();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
y=dis[i][j];
// if(dis[s1][i]>=0x3f3f3f3f||dis[s2][i]>=0x3f3f3f3f||dis[j][t1]>=0x3f3f3f3f||dis[j][t2]>=0x3f3f3f3f)continue;
x=dis[s1][i]+dis[s2][i]+dis[j][t1]+dis[j][t2];
x=min(x,dis[s1][i]+dis[t2][i]+dis[t1][j]+dis[s2][j]);
if(x>4*n||y>n)continue;
if(y<0||x<0)continue;
// cout<<x<<' '<<y<<endl;
Ans[y]=min(Ans[y],x);
}
}
lb ans=1e8;int tmp=(lb)(dis[s1][t1]+dis[s2][t2]);
if(!tmp){
cout<<0;return 0;}
int qt=k/tmp,kt=k%tmp;
ans=((lb)(tmp-kt))/((lb)qt+1)+((lb)kt)/((lb)qt+2);
for(int i=1;i<=n;i++)
{
if(Ans[i]>4*n)continue;
int l=0,r=k,lmid,rmid;
while(r-l>=1000)
{
int len=r-l+1;
lmid=l+len/3;rmid=r-len/3;
lb ra=cale(i,Ans[i],rmid);lb la=cale(i,Ans[i],lmid);
ans=min(ans,min(la,ra));
if(la<ra){r=rmid;}
else{l=lmid;}
}
for(int j=l;j<=r;j++)ans=min(ans,cale(i,Ans[i],j));
}
printf("%.12Lf",ans);
return 0;
}