1. 程式人生 > >2017.12.23 浙江工大 迎新賽

2017.12.23 浙江工大 迎新賽

由於 示例 pen 多少 div 不同的 輸入 分析 oid

A .

題目描述

小傑是學院中公認的計算機大神,有一天小傑受邀去機房幫忙接網線,他三下五除二地就幫忙完成了。可是善於思考地他仍意有未盡,他覺得這次的線路有許多奇妙的性質,故來請教你。
機房有n臺不同的主機(編號為0,1,2,?,n?1),共連有n條網線,每臺主機恰連著兩條網線,通向其他的主機。相互之間有網線相連的主機可以通信,主機可以轉發其他主機的信息,換句話說,如果主機A和主機C可以通信,主機B和主機C可以通信,那麽主機A和主機B可以通信。現在想在一些主機間添加一些網線,使得任意一個主機故障時,其他的主機之間仍能互相通信(註:在一個主機故障時,所有與該主機直接相連的線路將無法使用)。那麽問題來了,在添加的網線最少時,請問有多少種連線的方案,由於連線方案可能非常多,請將方案數對1000,000,007取模。

輸入描述:

第一行表示主機數n。
接下來有n行,第i(i=0,1,2,?,n?1)行有兩個數a,b,表示主機i和主機a,主機i和主機b各有網線相連。
輸入有多組數據,n=0時,表示輸入結束,請不要有對該組數據任何輸出。

輸出描述:

每組數據輸出一行,表示方案數對1000,000,007取模的結果。(行末不要有多余的空白字符)
示例1

輸入

5
2 3
4 4
0 3
0 2
1 1
12
11 11
10 10
9 9
8 8
7 7
6 6
5 5
4 4
3 3
2 2
1 1
0 0
2
1 1
0 0
0

輸出

6
3
0

備註:

2≤n≤3×105, 不超過10組數據 n≥2×105, 不超過20組數據 n≥104, 總數據組數不超過200 題目分析 : 其實題目就是讓找有多少個聯通的圖,並且找到每個獨立的圖中有多少個點,要將所有的圖都連通,且保證當只有一個主機壞的時候,其他主機仍保持連通,則可以從每個獨立的塊中選擇兩個點出來去進行相連,C(n, 2),每面對兩個獨立的圖,則會在乘以 2 ,因為可以交換點的順序麽,然後再是所有獨立連通圖的排列順序,有(n-1)! 種 。 補充兩個很坑的點 !!! 並查集的路徑壓縮部分,以前學的版本他路徑壓縮是不完全的 !! , 必須得最後在遍歷一遍補充一些點進行路徑壓縮 !!! 第二點就是 long long 的地方, 拼經驗的地方, long long ans 要先給大數值 !!! 雖然還不知道為什麽 !!
#define ll long long
const int eps = 3e5+5;
const ll mod = 1000000007;
const double pi = acos(-1.0);
const int inf = 1<<29;
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a


int f[eps];
int num[eps];
int n;
ll jc[eps];
ll fang[eps];

int fid(int x){
    //return x==f[x]?x:fid(f[x]);
    int r = x;
    while(r != f[r]){
        r = f[r];
    }
    
    int p = x;
    while(p != r){
        int t = f[p];
        f[p] = r;
        p = t;
    }
    return r;
}

void fun(){
    fang[0] = 1;
    jc[0] = 1;
    for(ll i = 1; i <= 300000; i++){
        jc[i] = jc[i-1]*i;
        fang[i] = fang[i-1]*2;
        jc[i] %= mod;
        fang[i] %= mod;
    }
}

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    int a, b;
    fun();
    map<int, int>mp;
    
    while(~scanf("%d", &n) && n){
        for(ll i = 0; i <= 300000; i++) f[i] = i;
        for(int i = 0; i < n; i++){
            scanf("%d%d", &a, &b);
            int fi = fid(i);
            int fa = fid(a);
            if (fi != fa){
                f[fa] = fi;
            }
            int fb = fid(b);
            if (fi != fb) f[fb] = fi;
        }
         
        mp.clear();
        for(int i = 0; i < n; i++){
            f[i] = fid(i);   // 補充路徑壓縮 !!
            mp[f[i]]++;
        }
         
        int cnt = mp.size();
        map<int, int>::iterator it;
        
        ll ans = jc[cnt-1]*fang[cnt-1]%mod;
        //ll ans = 1;  // 這樣寫就有問題了 !!! 雖然不知道為什麽 
        for(it = mp.begin(); it != mp.end(); it++){
            int t = it->second; 
            ans *= 1ll*t*(t-1)/2%mod;
            ans %= mod;
        }
        //ans *= jc[cnt-1]%mod;  
        //ans *= fang[cnt-1]%mod;
        //ans %= mod;
        if (cnt == 1) printf("0\n");
        else
            printf("%lld\n", ans%mod);
    }
    
    return 0;
}

2017.12.23 浙江工大 迎新賽