zoukankan      html  css  js  c++  java
  • 【BZOJ 1016】 [JSOI2008]最小生成树计数(matrix-tree定理做法)

    【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1016

    【题意】

    【题解】

    /*
        接上一篇文章;
        这里用matrix-tree定理搞最小生成树个数;
        对于每一种相同边权的边;
        当做一个阶段;
        这个阶段,我们需要看看这个边权的边能连接哪些联通块;
        这里的联通块可以缩为一个点;
        这样就相当于在一些点中间插入边;
        然后问你这些边能够生成的生成树的个数;
        即每个阶段都做一遍matrix-tree定理;
        martrix-treee定理想要做的话;
        你得先得出一张图,最好弄出它的邻接矩阵;
        然后可以这样吧。
        把这张图缩点之后的节点都标成新的节点;
        然后根据新添加进来的边;
        建立一张新的图,
        然后在这张新图上求生成树;
        根据前一篇的分析可知这样的生成树一定是最小生成树的一部分;
        建立新图的话也不会难吧;
        如果节点之前没出现过就递增节点就好;
        然后统计这张新图里面节点的个数;
        然后处理出邻接矩阵和度数就能搞了;
        不过这样处理会有重边的哦;
        当然这个定理也能处理有重边的情况,所以不慌.
        每次把生成树的个数根据乘法原则乘到答案上就好
        (新的图上可能会有多个连通块,要每个连通块分别算,不然整张图都不是联通的,你再用
        整张图去求的话会出错)
        (初始化什么的一定要认真检查啊);
        (这个行列式的求法不要用double类,不然精度不够,用int。。不知道为什么可以用int..)
    */


    推荐一个题解吧
    http://www.cnblogs.com/flipped/p/5769228.html
    要记住是度数矩阵减去邻接矩阵啊.

    【完整代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%lld",&x)
    
    typedef pair<int, int> pii;
    typedef pair<LL, LL> pll;
    
    const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
    const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
    const double pi = acos(-1.0);
    const int N = 110;
    const int M = 1e3 + 100;
    const int MOD = 31011;
    
    
    struct abc
    {
        int x, y, z;
    };
    
    int n, m,tot,cnt = 0;
    int f[N],D[N][N],A[N][N],C[N][N],ka[N],g[N][N];
    int bo[N];
    abc bian[M];
    double a[N][N];
    vector <int> v[N];
    long long ans = 1;
    
    bool cmp1(abc a, abc b)
    {
        return a.z < b.z;
    }
    
    int ff(int x)
    {
        if (f[x] == x) return x;
        else
            return f[x] = ff(f[x]);
    }
    
    int fk(int x)
    {
        if (ka[x] == x) return x;
        else
            return ka[x] = fk(ka[x]);
    }
    
    int cl(int c[N][N], int n) {
        int i, j, k, t, ret = 1;
        for (i = 1; i<=n-1; i++) {
            for (j = i + 1; j<=n-1; j++)
                while (c[j][i]) {
                    t = c[i][i] / c[j][i];
                    for (k = i; k<n; k++)
                        c[i][k] = (c[i][k] - c[j][k] * t) % MOD;
                    swap(c[i], c[j]);
                    ret = -ret;
                }
            if (c[i][i] == 0)
                return 0;
            ret = ret*c[i][i] % MOD;
        }
        return (ret + MOD) % MOD;
    }
    
    int main()
    {
        //freopen("F:\rush.txt", "r", stdin);
        rei(n), rei(m);
        rep1(i, 1, m)
            rei(bian[i].x), rei(bian[i].y), rei(bian[i].z);
        sort(bian + 1, bian + 1 + m,cmp1);
        ans = 1;
        rep1(i, 1, n)
            f[i] = i,ka[i] = i;
        rep1(i, 1, m)
        {
            int l = i, r = i;
            while (r + 1 <= m && bian[r + 1].z == bian[l].z) r++;
            rep1(j, 1, n)
                rep1(jj, 1, n)
                g[j][jj] = 0;
            rep1(j, 1, n)
                bo[j] = 0;
            rep1(j, l, r)
            {
                int x = bian[j].x, y = bian[j].y;
                int r1 = ff(x), r2 = ff(y);
                if (r1 != r2)
                {
                    int rr1 = fk(r1), rr2 = fk(r2);
                    if (rr1 != rr2)
                        ka[rr1] = rr2;
                    bo[r1] = true, bo[r2] = true;
                    g[r1][r2]++, g[r2][r1]++;
                }
            }
            rep1(j, 1, n)
                v[j].clear();
            rep1(j, 1, n)
                if (bo[j])
                    v[fk(j)].push_back(j);
    
            rep1(j,1,n)
                if (int(v[j].size()) > 1)
                {
                    rep1(k, 1, n)
                        rep1(kk, 1, n)
                            D[k][kk] = A[k][kk] = 0;
                    int len = v[j].size();
                    rep1(k,0,len-2)
                        rep1(l, k + 1, len - 1)
                        {
                            int x = v[j][k], y = v[j][l];
                            if (g[x][y])
                            {
                                D[k+1][k+1] += g[x][y], D[l+1][l+1] += g[x][y];
                                A[l+1][k+1] = A[k+1][l+1] = g[x][y];
                            }
                        }
                    rep1(k, 1,len )
                        rep1(kk, 1, len)
                            C[k][kk] = D[k][kk] - A[k][kk];
                    tot = len;
                    ans = (ans*cl(C,len)) % MOD;
                }
            rep1(j, l, r)
            {
                int x = bian[j].x, y = bian[j].y;
                int r1 = ff(x), r2 = ff(y);
                if (r1 != r2)
                {
                    f[r1] = r2;
                    cnt++;
                }
            }
            rep1(j, 1, n)
                ka[j] = f[j];
            i = r;
        }
        if (cnt != n - 1)
            return puts("0"),0;
        printf("%lld
    ", ans);
        return 0;
    }
  • 相关阅读:
    输入输出重定向
    MarkdownPad 2中编辑
    (转)Maven最佳实践:划分模块
    (转)maven设置内存
    我收集的sonar参考资料
    (转)linux service理解
    制作service服务,shell脚本小例子(来自网络)
    6
    4
    5
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626581.html
Copyright © 2011-2022 走看看