[予約] $ Luogu $ $ $ P4951説明

オリジナルを読みます

二項は、良い質問に答えます!

この古来の質問(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;
}

おすすめ

転載: www.cnblogs.com/Peter0701/p/11298181.html