[Bzoj3925] [羅区P3343] [ZJOI2015]地震幻想郷の後

説明

ふざけて女の子の香りが非常に非常に孟孟の姉妹で、彼女は彼らを助けるために人々のファンタジー村のために物事を行うにはその力の一部の非常に好き、非常に、非常に愛情でした。これは、突然、すべての道路が崩壊した地震があったが、ファンタジーの村ではありません。主なタスクは今、できるだけ早く再確立錯覚農村交通システムを作ることです。

ファンタジー町の合計\(N \)に代え、次に最速の方法で修復することである(N-1 \)を\道路これら\(N \)の場所が接続されています。この錯覚を追加(\ N-)\元々通信、の合計配置\(Mの\)エッジを。今では\(m個\)がすべてを破壊し、震災の端。各側は、それがかかる修正時間を持って、最初の\(私は\)エッジのに必要な時間\(EI \) 香りが豊かな人生経験であり、各以降の地震を知って、彼女の以前の経験に基づいて、高齢者のより多くを見るので、地震の後、各\(EI \)が均等に0と1の間で分配されますランダムな実数。そして、すべての\(EI \)は完全に独立しています。

今、道路の修復を助けるためにオフfragrance're、と彼女は魔法の大きな魔法を使うことができ、あなたが必要なを選択することができます\(N-1 \)エッジ、および修復し始め、完了するまでに修理時間がこれです\(N-1 \)エッジの\(EI \)最高。もちろん、香りが最初にすべてのエッジの大魔法を観察するために多くの魔法を使用します\(EI \)の値にして、プログラムを完了するための最小時間を選択します。離れる前にフレグランスは、彼女は期待の修理が完了するまでの時間はどのくらい知っているしたいですか?

入力

最初の2つの行番号\(N- \) \(m個\) およびエッジが場所の数を表します。請求項1から点へ\(N- \)参照。\(m個\) 2つの数の行\(\) \(B \) ポイントを表し\(\)と点(\ Bの\)の一方の側との間に存在すること。これは、複数のエッジや図のループバックを持っていません。

出力

ライン出力は、答えは小数点以下6桁に丸められました。

サンプル入力

5 4
1 2
1 5
4 3
5 3

サンプル出力

0.800000

ヒント

(以下は質問の意味とは何の関係もありません、またそれは、問題解決のために必要です。)

以下のための\(\ N-) 2 [0,1]の間のランダム変数\(X1、X2、...、Xnの\) 最初の\(K \)所望の値であることが小さい\(K /(N + 1)\)

サンプルは説明しました:

最初のサンプルでは、唯一の4辺と、この香りはその後、答えは四方で、4を選択することは明らかである(EI \)\プロンプト、明確な答えの内容によって期待される最大数を0.8。

データ範囲:

:すべてのデータのための\(N- \のLeq 10 \) \(m個の\ n型のLeq(N - 1)/ 2 \)、N- $、M \ $ GEQ 1。

データの15%:\(N- \のLeq 3 \)

データの別の15%:\(N- \ leq10、N-M = \)

データの別の10%:\(N- \のLeq 10、N-M =(N - 1)/ 2 \。)

データの別の20%:\(N- \ leq5 \)

データの別の20%:\(N- \ leq8 \)


考え

一見タイトルは、うんうんうん条件ので、いくつかは、迅速なカウントああを期待して!
プロンプト、参照するには第二の目\(\ ... emmm) 彼のかどうかは##の後ろに)

私たちが知っていれば、まず第一に、ということ\(EI \)正確な値は、あなたが置くことができます\(EI \)を小から大まで、その後、\(クラスカル\) ちょうど最小スパニングツリーがコラージュに参加する最後のものである構成することは正しい答えです。
これは、暴力的な取得する方法である:もう一度、すべての辺の相対的な大きさを列挙して、再度実行します(クラスカル\)\平均回数の後。

そして、最適化する方法を検討してください。
仮定\(クラスカルを\)最初の最後のエッジ最小スパニングツリー中に添加した\(Iは\)小さい、解答への寄与をする\(P(I)\回 \ FRAC {I} {M + 1 } \)、\ (P(I)\)確率プラス正確に設定された最小スパニングツリーエッジを表します。
次に\(ANS = \和\ limits_ {i = 1} ^ {M} P(I)\回\ FRAC {I} {M + 1} = FRAC \ {1} {M + 1} \和\ limits_ { I = 1} ^ {M}
P(I)iは\回\) と\(P(I)倍\ iは\) として解釈することができる\(P(I)\)を添加した\(Iは\)\(ANS = \ FRAC {1 } {M + 1} \和\ limits_ {i = 1} ^ {M} \和\ limits_ {J =} ^ {M} P(J)\)

我々は、このことの背後に見える\(J limits_ \ SUM \ = I {M}} ^ {P(J)\)と意味、\(I-1 \)スパニングツリー側、すなわち、図中に作ることができない(形成することができません。ユニコムの確率)、およびとして設定\(P「(1-I)\)
明らかに、\(P「(I)= \ {図ユニコムの実施の形態におけるエッジの数ではないIから選択FRAC} {C_ {M} ^ { I}} \)

したがって、我々は主張は、以下から選択される\(Iは\)ユニコムは、元のプログラムの数ではない縁
観察\(n-は\)非常に小さい非常に、我々は、成形圧力列挙サブセット考える\(DP \)が
配置された\(Fを[ I] [J] [0/1] \) 点の集合を表す\(Iは\)選択中の\(J \)点セット/プログラム番号ユニコムを通信しない縁部、

探している\(F [I] [jを ] [0] \) :先端ときに使用される
点の集合が\(Iは\)二つの互いにユニコム点集合に分割され、一点に設定ユニコム、別のセットポイントは、このプログラムの要件を満たすために保証され、重要ではありません。
そう!点のセットを見て(私は\)\\(T \)列挙に含まを\(T \) A \(I \)サブセット\(K \)ので、辺の数から選択され、\(K \)ユニコム、点の集合は、\(IK \)図は、サブ残りのエッジを生成する選択されました。
セット\(サイズは、[I] \)点の集合を表し(Iは\)\のサブグラフを生成するエッジの数を。
次に、状態遷移方程式は:
\(F [I] [J] [0] = \ SUM \ limits_ {K \サブセットIにおけるT \} \ SUM \ limits_ {S = 0} ^ {MAX(サイズ[K]、 F J)} [K] [ S] [1] \回C_ {サイズ[I ^ K]} ^ {JS} \)

我々は知っているので([I] [J] F [0] + F [I] [J] [1] = {C_サイズ[I]} ^ {J} \)\、我々は入手I [F(\を] [J] 0] \ [ ) リゾートの後\(F [I] [J ] [1] = C_ {サイズ[I]} ^ {J} -f [I] [J] [0] \)

最後に、\(ANS = \ FRAC {1} {M + 1} \ SUM \ limits_ {I = 1} ^ {M} \ FRAC {F [コレクション] [I-1] [0 ]}、{C_ {M} ^ {I}} \)


コード

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

int read(){
    int x=0;
    char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x;
} 

const int N = 2048;
typedef long long ll;

int n,m,w;
int size[N],u[100],v[100];
ll f[N][100][2],c[100][100];

int main()
{
    n=read(); m=read();
    for(int i=0;i<m;i++) u[i]=read(),v[i]=read();
    
    w=(1<<n)-1;
    for(int i=1;i<=w;i++)
        for(int j=0;j<m;j++)
            if((i&(1<<(u[j]-1))) && (i&(1<<(v[j]-1)))) size[i]++;
    
    c[0][0]=1;
    for(int i=1;i<=m;i++){
        c[i][0]=c[i][i]=1;
        for(int j=1;j<i;j++)
            c[i][j]=c[i-1][j-1]+c[i-1][j];
    }
    for(int i=1;i<=w;i++){
        int t=i&(-i); //注意!这里不要轻易给f[i][0][0]与f[i][0][1]赋初值!!!
        for(int j=0;j<=size[i];j++){
            for(int k=(i-1)&i;k;k=(k-1)&i){
                if(!(k&t)) continue;
                for(int l=0;l<=j && l<=size[k];l++)
                    f[i][j][0]+=f[k][l][1]*c[size[i^k]][j-l];
            }
            f[i][j][1]=c[size[i]][j]-f[i][j][0];
        }
    }
    
    double ans=0;
    for(int i=0;i<m;i++) ans+=1.0*f[w][i][0]/(double)c[m][i];
    printf("%.6lf\n",ans/(m+1.0));
    
    return 0;
}

おすすめ

転載: www.cnblogs.com/lindalee/p/11073464.html