2017.12.23 浙江工大 迎新賽
阿新 • • 發佈:2017-12-24
由於 示例 pen 多少 div 不同的 輸入 分析 oid
機房有n臺不同的主機(編號為0,1,2,?,n?1),共連有n條網線,每臺主機恰連著兩條網線,通向其他的主機。相互之間有網線相連的主機可以通信,主機可以轉發其他主機的信息,換句話說,如果主機A和主機C可以通信,主機B和主機C可以通信,那麽主機A和主機B可以通信。現在想在一些主機間添加一些網線,使得任意一個主機故障時,其他的主機之間仍能互相通信(註:在一個主機故障時,所有與該主機直接相連的線路將無法使用)。那麽問題來了,在添加的網線最少時,請問有多少種連線的方案,由於連線方案可能非常多,請將方案數對1000,000,007取模。
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 浙江工大 迎新賽