JSOI2008 最小生成樹計數

2022-08-12 16:24:17 字數 3728 閱讀 8700

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

1

program 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 的邊將這些連通塊連成一棵樹...