• P4208 [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的模就可以了。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define duke(i,a,n) for(register int i = a;i <= n;++i)
    #define lv(i,a,n) for(register int i = a;i >= n;--i)
    #define clean(a) memset(a,0,sizeof(a))
    const int INF = 1 << 30;
    typedef long long ll;
    typedef double db;
    template <class T>
    void read(T &x)
    {
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x)
    {
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    const int N = 2010;
    const int mod = 31011;
    struct node
    {
        int l,r,w;
    }e[N];
    int f[N];
    struct rdq
    {
        int left,right,va;
    }a[N];
    int m,n,cnt = 0,ans,sum = 0;
    bool cmp(node a,node b)
    {
        return a.w < b.w;
    }
    int find(int x)
    {
        if(f[x] == x)
        return x;
        else
        return find(f[x]);
    }
    void dfs(int x,int now,int k)
    {
        if(now == a[x].right + 1)
        {
            if(k == a[x].va)
            {
                sum++;
            }
            return;
        }
        int xx = find(e[now].l),yy = find(e[now].r);
        if(xx != yy)
        {
            f[xx] = yy;
            dfs(x,now + 1,k + 1);
            f[xx] = xx;
            f[yy] = yy;
        }
        dfs(x,now + 1,k);
    }
    int main()
    {
        read(n);read(m);
        duke(i,1,n)
            f[i] = i;
        duke(i,1,m)
        {
            read(e[i].l);read(e[i].r);read(e[i].w);
        }
        sort(e + 1,e + m + 1,cmp);
        int tot = 0;
        for(int i = 1;i <= m;++i)
        {
            if(e[i].w != e[i - 1].w) cnt++,a[cnt].left = i,a[cnt - 1].right = i - 1;
            int xx = find(e[i].l),yy = find(e[i].r);
            if(xx != yy)
            {
                f[xx] = yy;
                a[cnt].va ++;
                tot++;
            }
        }
        if(tot != n - 1)
        {
            printf("0
    ");
            return 0;
        }
        a[cnt].right = m;
        ans = 1;
        duke(i,1,n)
        f[i] = i;
        duke(i,1,cnt)
        {
            sum = 0;
            dfs(i,a[i].left,0);
            ans = (ans * sum) % mod;
            for(int j = a[i].left;j <= a[i].right;++j)
            {
                int xx = find(e[j].l),yy = find(e[j].r);
                if(xx != yy)
                {
                    f[xx] = yy;
                }
            }
        }
        printf("%d
    ",ans);
        return 0;
        
    }
  • 相关阅读:
    最小生成树
    图论最短路径例题
    广搜例题
    这些搜索套路好深。。。
    高斯消元part2
    高斯消元与行列式求值 part1
    2020/4/24
    实时的眼部追踪
    2020/4/23
    2020/4/22
  • 原文地址:https://www.cnblogs.com/DukeLv/p/10519945.html
Copyright © 2020-2023  润新知