zoukankan      html  css  js  c++  java
  • [BZOJ1016] [JSOI2008] 最小生成树计数 (Kruskal)

    Description

      现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的
    最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生
    成树可能很多,所以你只需要输出方案数对31011的模就可以了。

    Input

      第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整
    数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,0
    00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

    Output

      输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

    Sample Input

    4 6
    1 2 1
    1 3 1
    1 4 1
    2 3 2
    2 4 1
    3 4 1

    Sample Output

    8

    HINT

    Source

    Solution

      最小生成树的性质:

    1. 对于每一个$MST$,每一种边权所使用的边数相同
    2. 所有$MST$中边权$leq w$的边组成的图的连通性相同

      所以首先我们可以用$Kruskal$算出每一种边权使用的边数

      之后暴力枚举某种边权所使用的边

      因为最多只有$10$条边,所以时间可以接受,当没有这个限制条件时需要用到$Matrix$-$Tree$定理。对,你知道的,我不会这个

      顺便试着写了下冰炸鸡并查集按秩合并,稍微伪证了一下发现是$O(nlogn)$的,不过可以撤回?!好像又解锁了什么姿势

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 struct edge
     4 {
     5     int u, v, w, x;
     6     inline bool operator< (const edge &rhs) const
     7     {
     8         return x < rhs.x;
     9     }
    10 }e[1005];
    11 struct count
    12 {
    13     int l, r, use;
    14 }g[1005];
    15 int n, m, fa[105], siz[105];
    16   
    17 int getfa(int x)
    18 {
    19     return fa[x] == x ? x : getfa(fa[x]);
    20 }
    21   
    22 void link(int u, int v)
    23 {
    24     if(siz[u] > siz[v]) fa[v] = u, siz[u] += siz[v];
    25     else fa[u] = v, siz[v] += siz[u];
    26 }
    27   
    28 bool Kruskal()
    29 {
    30     int cnt = 0, u, v;
    31     for(int i = 1; i <= m; ++i)
    32     {
    33         u = getfa(e[i].u), v = getfa(e[i].v);
    34         if(u != v)
    35         {
    36             link(u, v);
    37             ++g[e[i].w].use;
    38             if(++cnt == n - 1) return true;
    39         }
    40     }
    41     return false;
    42 }
    43   
    44 int DFS(int w, int i, int k)
    45 {
    46     if(k == g[w].use) return 1;
    47     if(i > g[w].r) return 0;
    48     int ans = 0, u = getfa(e[i].u), v = getfa(e[i].v);
    49     if(u != v)
    50     {
    51         link(u, v);
    52         ans = DFS(w, i + 1, k + 1);
    53         fa[u] = u, fa[v] = v;
    54     }
    55     return ans + DFS(w, i + 1, k);
    56 }
    57   
    58 int main()
    59 {
    60     int u, v, w, ans;
    61     cin >> n >> m;
    62     for(int i = 1; i <= n; ++i)
    63         fa[i] = i, siz[i] = 1;
    64     for(int i = 1; i <= m; ++i)
    65     {
    66         cin >> u >> v >> w;
    67         e[i] = (edge){u, v, 0, w};
    68     }
    69     sort(e + 1, e + m + 1);
    70     w = 0;
    71     for(int i = 1; i <= m; ++i)
    72         if(e[i].x == e[i - 1].x) e[i].w = w;
    73         else
    74         {
    75             g[w].r = i - 1;
    76             e[i].w = ++w;
    77             g[w].l = i;
    78         }
    79     g[w].r = m;
    80     ans = Kruskal();
    81     for(int i = 1; i <= n; ++i)
    82         fa[i] = i, siz[i] = 1;
    83     for(int i = 1; i <= w; ++i)
    84     {
    85         ans = ans * DFS(i, g[i].l, 0) % 31011;
    86         for(int j = g[i].l; j <= g[i].r; ++j)
    87         {
    88             u = getfa(e[j].u), v = getfa(e[j].v);
    89             if(u != v) link(u, v);
    90         }
    91     }
    92     cout << ans << endl;
    93     return 0;
    94 }
    View Code
  • 相关阅读:
    [USACO11JAN]Roads and Planes G【缩点+Dij+拓补排序】
    Cheatsheet: 2015 05.01 ~ 05.31
    Cheatsheet: 2015 04.01 ~ 04.30
    Cheatsheet: 2015 03.01 ~ 03.31
    Cheatsheet: 2015.02.01 ~ 02.28
    Cheatsheet: 2015 01.01~ 01.31
    Cheatsheet: 2014 12.01 ~ 12.31
    Cheatsheet: 2014 11.01 ~ 11.30
    Cheatsheet: 2014 10.01 ~ 10.30
    Cheatsheet: 2014 09.01 ~ 09.30
  • 原文地址:https://www.cnblogs.com/CtrlCV/p/5585599.html
Copyright © 2011-2022 走看看