zoukankan      html  css  js  c++  java
  • _bzoj1016 [JSOI2008]最小生成树计数【生成树】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1016

    其实原题不叫这个的,而且原题是有一个背景故事的。。。

    首先,容易得知,一个最小生成树不管是什么样的,同一种长度的边出现的次数是一样的。而且由Kruscal的过程,若当前节点对整个图减少一个联通块有贡献,则加这条边,也就是说在比当前边短的边已经全部考虑完后,与当前边一样长的所有边对整个图的连通性的贡献是一样的。则,若最小生成树中与当前边一样长的边出现了x次,共有tot条,那么暴力枚举C(tot, x)次,若它们不构成环,则是合法的。最后对每种长度的边乘法原理一下就ok咯~

    注意题目陷阱:原图有可能没有生成树,此时输出0!

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
     
    const int maxn = 105, maxm = 1005, mod = 31011;
     
    int n, m, fa[maxn], num[maxm], cnt, t_fa[15][maxn], idx, fu, fv, ans, t_ans;
    int head[maxm], to[maxm], next[maxm], lb, max_step;
    struct Edge {
        int u, v, ww, w;
    } a[maxm];
     
    bool cmp(const Edge & aa, const Edge & ss) {
        return aa.ww < ss.ww;
    }
    int getfa(int * ff, int aa) {
        return ff[aa] == aa? aa: ff[aa] = getfa(ff, ff[aa]);
    }
    inline void ist(int aa, int ss) {
        to[lb] = ss;
        next[lb] = head[aa];
        head[aa] = lb;
        ++lb;
    }
    void dfs(int step, int now) {
        if (step == max_step) {
            ++t_ans;
            return;
        }
        for (int j = next[now]; j != -1; j = next[j]) {
            fu = getfa(t_fa[step - 1], a[to[j]].u);
            fv = getfa(t_fa[step - 1], a[to[j]].v);
            if (fu == fv) {
                continue;
            }
            memcpy(t_fa[step], t_fa[step - 1], sizeof fa);
            t_fa[step][fu] = fv;
            dfs(step + 1, j);
        }
    }
     
    int main(void) {
        //freopen("in.txt", "r", stdin);
        memset(head, -1, sizeof head);
        memset(next, -1, sizeof next);
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i) {
            fa[i] = i;
        }
        for (int i = 0; i < m; ++i) {
            scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].ww);
        }
        std::sort(a, a + m, cmp);
        a[0].w = 1;
        idx = 1;
        ist(1, 0);
        for (int i = 1; i < m; ++i) {
            if (a[i].ww == a[i - 1].ww) {
                a[i].w = idx;
            }
            else {
                a[i].w = ++idx;
            }
            ist(a[i].w, i);
        }
         
        memcpy(t_fa[0], fa, sizeof fa);
        for (int i = 0; i < m; ++i) {
            fu = getfa(fa, a[i].u);
            fv = getfa(fa, a[i].v);
            if (fu != fv) {
                fa[fu] = fv;
                ++num[a[i].w];
                if (++cnt == n - 1) {
                    break;
                }
            }
        }
        if (cnt < n - 1) {
            puts("0");
            return 0;
        }
        memcpy(fa, t_fa[0], sizeof fa);
         
        ans = 1;
        for (int i = 1; i <= n; ++i) {
            fa[i] = i;
        }
        for (int i = 1; i <= idx; ++i) {
            if (!num[i]) {
                continue;
            }
            max_step = num[i];
            t_ans = 0;
            for (int j = head[i]; j != -1; j = next[j]) {
                fu = getfa(fa, a[to[j]].u);
                fv = getfa(fa, a[to[j]].v);
                if (fu == fv) {
                    continue;
                }
                memcpy(t_fa[0], fa, sizeof fa);
                t_fa[0][fu] = fv;
                dfs(1, j);
            }
            for (int j = head[i]; j != -1; j = next[j]) {
                fu = getfa(fa, a[to[j]].u);
                fv = getfa(fa, a[to[j]].v);
                if (fu != fv) {
                    fa[fu] = fv;
                }
            }
            ans = ans * t_ans % mod;
        }
        printf("%d
    ", ans);
        return 0;
    }
    

      

  • 相关阅读:
    《构建之法》第8、9、10章的读后感和第一个sprint总结
    实验三 进程调度模拟程序
    构建之法第6、7章的读后感
    实验二 作业调度模拟程序
    0415博客园评价
    0414复利计算6.0-----结对编程
    0408~送给小伙伴的汉堡包
    学习进度条
    Sprint three
    sprint one
  • 原文地址:https://www.cnblogs.com/ciao-sora/p/6184715.html
Copyright © 2011-2022 走看看