BZOJ1016 [JSOI2008]最小產生樹計數

來源:互聯網
上載者:User

標籤:io   os   for   sp   on   amp   ad   ef   size   

題意:給定一張n<=100,m<=1000的無向圖,另外相同權值的邊不超過10條,求最小產生樹的數目。


思路:首先我們將不同的權值從小到大分開考慮。


我們證明以下定理:一個無向圖所有的最小產生樹中某種權值的邊的數目均相同。

開始時,每個點單獨構成一個集合。

首先只考慮權值最小的邊,將它們全部添加進圖中,並去掉環,由於是全部嘗試添加,那麼只要是用這種權值的邊能夠連通的點,最終就一定能在一個集合中。

那麼不管添加的是哪些邊,最終形成的集合數都是一定的,且集合的劃分情況一定相同。那麼真正添加的邊數也是相同的。因為每添加一條邊集合的數目便減少1.

那麼權值第二小的邊呢?我們將之間得到的集合每個集合都縮為一個點,那麼權值第二小的邊就變成了當前權值最小的邊,也有上述的結論。

因此每個階段,添加的邊數都是相同的。我們以權值劃分階段,那麼也就意味著某種權值的邊的數目是完全相同的。


於是我們考慮做法。

首先做一遍最小產生樹看一下每種權值的邊出現了幾次。若不能構成產生樹輸出0.

然後考慮每一個階段:從小到大處理每一種權值的邊,狀壓枚舉所有這種權值的邊,看這種權值的邊出現指定次數時能否全部加入當前的森林。若能,則這個階段的數目+1.

那麼答案就是每個階段的數目的乘積。


對於每一個階段,我們也可以不用暴力枚舉,而用O(N^3)的Matrix-Tree定理求解行列式。若相同權值的邊數過多的話就只能用這種方法了。


Code:(狀態壓縮)

#include <map>#include <cstdio>#include <cctype>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define N 110int n, m;struct Edge {int f, t, len;void read() {scanf("%d%d%d", &f, &t, &len);}bool operator < (const Edge &B) const {return len < B.len;}}E[1010];map<int, int> M;int root[N], tmp[N];void reset() {for(int i = 1; i <= n; ++i)root[i] = i;}int find(int x) {int q = x, tq;for(; x != root[x]; x = root[x]);while(q != x) {tq = root[q];root[q] = x;q = tq;}return x;}int count(int x) {int res = 0;for(; x; x -= x & -x)++res;return res;}int _debug(int x) {return M[x];}#define Mod 31011int main() {scanf("%d%d", &n, &m);register int i, j, k;for(i = 1; i <= m; ++i)E[i].read();sort(E + 1, E + m + 1);int intree = 0, ra, rb;reset();for(i = 1; i <= m; ++i) {ra = find(E[i].f);rb = find(E[i].t);if (ra != rb) {++M[E[i].len];root[ra] = rb;if (++intree == n - 1)break;}}if (intree < n - 1) {puts("0");return 0;}int S, res = 1, now;reset();for(i = 1; i <= m; ) {for(j = i; E[j].len == E[j + 1].len; ++j);if (M[E[i].len]) {memcpy(tmp, root, sizeof root);now = 0;for(S = 1; S < (1 << (j - i + 1)); ++S) {if (count(S) != M[E[i].len])continue;memcpy(root, tmp, sizeof tmp);bool ac = 1;for(k = i; k <= j; ++k) {if ((S >> (k - i)) & 1) {ra = find(E[k].f);rb = find(E[k].t);if (ra == rb) {ac = 0;break;}root[ra] = rb;}}if (ac)++now;}res = res * now % Mod;memcpy(root, tmp, sizeof tmp);for(k = i; k <= j; ++k) {ra = find(E[k].f);rb = find(E[k].t);if (ra != rb)root[ra] = rb;}}i = j + 1;}printf("%d", res);return 0;}

BZOJ1016 [JSOI2008]最小產生樹計數

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.