jsoi2008 最小生成樹計數
【題目描述】
現在給出了乙個簡單無向加權圖。你不滿足於求出這個圖的最小生成樹,而希望知道這個圖中有多少個不同的最小生成樹。(如果兩顆最小生成樹中至少有一條邊不同,則這兩個最小生成樹就是不同的)。由於不同的最小生成樹可能很多,所以你只需要輸出方案數對31011的模就可以了。
【輸入檔案】
第一行包含兩個數,n和m,其中1<=n<=100; 1<=m<=1000; 表示該無向圖的節點數和邊數。每個節點用1~n的整數編號。接下來的m行,每行包含兩個整數:a, b, c,表示節點a, b之間的邊的權值為c,其中1<=c<=1,000,000,000。資料保證不會出現自回邊和重邊。注意:具有相同權值的邊不會超過10條。
【輸出檔案】
輸出不同的最小生成樹有多少個。你只需要輸出數量對31011的模就可以了。
【輸入樣例】
4 61 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
【輸出樣例】
8 【題目分析】
一開始超時了,加了半天優化發現快排寫錯了……
繼續……水題……首先按kruskal的思路做一遍最小生成樹,統計一下各個相同權值的邊分別加進去了幾條,然後對每組相同權值的邊進行dfs,計算對於每組邊有多少種加入先前計算出的邊的數量的方案,乘在一起即可。注意,dfs時並查集樸素合併,不要進行路徑壓縮,否則無法進行狀態還原,處理完每組邊後,修改連通性時再進行狀態壓縮。再次注意,有不連通的情況,此時輸出0。
【**實現】
code
1program tyvj1826;
2var s,t,l:array[0..1001]of longint;
3 f:array[0..1000]of longint;
4 g,ss:array[0..1000]of longint;
5 i,j,m,n,ans,k,p,ll,rr,x,y,sum:longint;
6procedure kp(ll,rr:longint);
7var i,j,x,y:longint;
8begin
9 i:=ll;j:=rr;
10 x:=l[(i+j)shr 1];
11repeat
12while l[i]do inc(i);
13while l[j]>x do dec(j);
14if i<=j then
15begin
16 y:=l[i];
17 l[i]:=l[j];
18 l[j]:=y;
19 y:=s[i];
20 s[i]:=s[j];
21 s[j]:=y;
22 y:=t[i];
23 t[i]:=t[j];
24 t[j]:=y;
25 inc(i);
26 dec(j);
27end;
28until i>j;
29if llthen kp(ll,j);
30if ithen kp(i,rr);
31end;
32function find(x:longint):longint;
33begin
34if x<>f[x] then f[x]:=find(f[x]);
35 exit(f[x]);
36end;
37procedure dfs(i,j:longint);
38var x,y:longint;
39begin
40if j=p then
41begin
42 inc(g[rr]);
43 exit;
44end;
45if i=rr+1
then exit;
46if rr-i+1+jthen exit;
47 dfs(i+1,j);
48 x:=s[i];y:=t[i];
49while x<>f[x] do x:=f[x];
50while y<>f[y] do y:=f[y];
51if x<>y then
52begin
53 f[x]:=y;
54 dfs(i+1,j+1);
55 f[x]:=x;
56end;
57end;
58begin
59 readln(n,m);
60for i:=1
to m do readln(s[i],t[i],l[i]);
61 kp(1,m);
62for i:=1
to n do f[i]:=i;
63 p:=0;sum:=0;
64for i:=1
to m do
65begin
66 x:=find(s[i]);y:=find(t[i]);
67if x<>y then
68begin
69 f[x]:=y;
70 inc(sum);
71 inc(p);
72end;
73if l[i]<>l[i+1] then
74begin
75 ss[i]:=p;
76 p:=0;
77end;
78end;
79if sum1
then
80begin
81 writeln(0);
82 halt;
83end;
84for i:=1
to n do f[i]:=i;
85 ll:=1;rr:=1;
86for i:=1
to m do
87begin
88if l[i]=l[i+1] then
89begin
90 inc(rr);
91 continue;
92end;
93 p:=ss[rr];
94 dfs(ll,0);
95for j:=ll to rr do
96begin
97 x:=find(s[j]);y:=find(t[j]);
98if x<>y then f[x]:=y;
99end;
100 ll:=i+1;rr:=i+1;
101end;
102 ans:=1;
103for i:=1
to m do
104if l[i]<>l[i+1] then ans:=ans*g[i] mod
31011;
105 writeln(ans);
106end.
JSOI2008 最小生成樹計數
time limit 1 sec memory limit 162 mb 現在給出了乙個簡單無向加權圖。你不滿足於求出這個圖的最小生成樹,而希望知道這個圖中有多少個不同的 最小生成樹。如果兩顆最小生成樹中至少有一條邊不同,則這兩個最小生成樹就是不同的 由於不同的最小生 成樹可能很多,所以你只需要輸出...
JSOI2008 最小生成樹計數
bzoj luogu 根據最小生成樹的一些性質,不同的最小生成樹固定權值的邊數是一樣的 而且我們發現這題同權的邊數 10 於是可以預處理出每種權值需要多少條邊,然後爆搜 然後不能路徑壓縮,不然你怎麼回溯.注意到n只有100,暴力並查集搜根沒有任何問題 複雜度 o 邊權數 2 最壞也就是 100 10...
JSOI 2008 最小生成樹計數 題解
題目傳送門 題目大意 求一張圖有多少棵最小生成樹。最小生成樹有個性質,就是每種長度的邊的數量是固定的。所以先隨便找一棵最小生成樹,考慮長度為 i ii 的邊,先將長度不為 i ii 的最小生成樹中的邊加入進去,然後就形成了若干個連通塊,然後剩下的問題就是用長度為 i ii 的邊將這些連通塊連成一棵樹...