二項は、良い質問に答えます!
この古来の質問(2001)が、しかし、USACOの知恵を疑問視する人duliuそれは私たちが疑問に思う作るん。
イタリアは無向グラフが与えられていることを述べ、それぞれの側は、時間$ tの$と利益を過ごしたの$ C $の、与えられたその他の報酬の$ fが$、平均シーク時間を持っています。
{ - \合計{} C_I F} {\ {合計T_I}} $我々はFRAC \平均時間利益$アンスの$、$ ANS =をとることができます。\和{C_I} - - 方程式$ Fを変換するために容易に利用できるANS * \ {合計T_I} = 0 $。
\和{C_I} - - 次関数$ F(ANS)はF = ANS * \和{T_I} $、明らかにFを$(ANS)$を現在の範囲内で問題の単調減少、単調です。
したがって、我々はこの質問を解決するために採用慣行の半分は$ ANS 2で割っ$のためにある答えることができます。
もちろん、答えの本質は常に二分法$チェック$関数です。この質問の答えの合法性を調べるために、前の式から$クラスカル$は$ \合計{C_I} +を計算することは容易である上で実行することにより、各エッジが$ C_I + ANS * T_Iの$に設定されている重み付けしたいと思うかもしれANS * \ {合計T_I} $、$ fが$答えは、この値より小さい場合には、それ以外の答えは大きすぎる、小さすぎます。
この時点で、この質問の終わり!残りの詳細はコードの下に表示されます。質問、コメントと修正の面積を有し、参照、あなたが見てありがとう!
さらに読書:最小比スパニングツリー
この問題はコード:
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int ret=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ret=(ret<<1)+(ret<<3)+ch-'0';
ch=getchar();
}
return ret*f;
}
int n,m,f,fa[405];
long long mid,l,r=2e15;
struct Edge
{
int x;
int y;
int c;
int t;
double w;
}edge[10005];
inline bool cmp(Edge a,Edge b)
{
return a.w<b.w;
}
inline int find(int x)
{
if(fa[x]==x)
return x;
return fa[x]=find(fa[x]);
}
inline bool check(long long mid)
{
for(register int i=1;i<=m;i++)
edge[i].w=mid/(3e6+0.0)*edge[i].t+edge[i].c;
int tmp=1;
sort(edge+1,edge+m+1,cmp);
for(register int i=1;i<=n;i++)
fa[i]=i;
double k=f+1e-12;
for(register int i=2;i<=n;i++)
{
while(tmp<=m&&find(edge[tmp].x)==find(edge[tmp].y))
tmp++;
fa[find(edge[tmp].x)]=find(edge[tmp].y),k-=edge[tmp].w;
if(k<0)
return false;
}
return true;
}
int main()
{
n=read();
m=read();
f=read();
for(register int i=1;i<=m;i++)
{
edge[i].x=read();
edge[i].y=read();
edge[i].c=read();
edge[i].t=read();
}
if(!check(0))
{
printf("0.0000\n");
return 0;
}
while(l<r)
{
mid=(l+r)>>1;
if(check(mid+1))
l=mid+1;
else
r=mid;
}
printf("%0.4lf\n",l/(3e6+0.0));
return 0;
}