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

    题目链接

    Solution [JSOI2008]最小生成树计数

    题目大意:给定一张(n)个点(m)条边无向图,保证具有相同边权的边不超过(10)条,(n leq100,mleq1000),求不同最小生成树个数

    最小生成树、计数


    分析:

    做这题需要用到一个结论:

    所有最小生成树,把边权按照升序排列之后,得到的序列是一样的。也就是说对于最小生成树而言,每种边权的边选了多少条是确定的

    此外,按照边权升序的顺序加边,把一种边权的边全部加完之后,所有生成树的连通性是相同的。

    由于具有相同边权的边的数量较少我们可以暴力

    先跑一遍最小生成树求出每种边权选择的数量,然后对每种边权暴力统计合法方案数,最后用乘法原理计算答案

    判断两个图连通性是否相同可以使用并查集,如果(A)图每个点所在的联通块编号序列可以通过某种置换得到(B)图对应序列,那么(A,B)两个图的连通性就是相同的

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn = 128,maxm = 1024,mod = 31011;
    inline int read(){
        int x = 0;char c = getchar();
        while(!isdigit(c))c = getchar();
        while(isdigit(c))x = x * 10 + c - '0',c = getchar();
        return x;
    }
    struct edge{
        int u,v,d;
        bool operator < (const edge &rhs)const{
            return d < rhs.d;
        }
    }edges[maxm];
    int n,m,tot,last,num,mem[16],trans[maxn],ans = 1,cnt;
    struct mset{
        int f[maxn],sz;
        inline void init(){
            for(int i = 1;i <= n;i++)f[i] = i;
            sz = n;
        }
        inline int find(int x){return x == f[x] ? x : f[x] = find(f[x]);}
        inline void merge(int a,int b){
            int x = find(a),y = find(b);
            f[x] = y;sz--;
        }
    }s,tmp,lass;
    inline void out(){
        tmp = lass;
        for(int i = 1;i <= num;i++){
            int x = tmp.find(edges[mem[i]].u),y = tmp.find(edges[mem[i]].v);
            if(x == y)return;
            tmp.merge(x,y);
        }
        for(int i = 1;i <= n;i++)tmp.f[i] = tmp.find(tmp.f[i]);
        memset(trans,0,sizeof(trans));
        for(int i = 1;i <= n;i++){
            if(!trans[lass.f[i]])trans[lass.f[i]] = tmp.f[i];
            if(trans[lass.f[i]] != tmp.f[i])return;
        }
        cnt++;
    }
    inline void dfs(int now,int pos,int mx){
        if(pos == num + 1){
            out();
            return;   
        }
        if((mx - now + 1) < (num - pos + 1))return;
        mem[pos] = now;
        dfs(now + 1,pos + 1,mx);
        dfs(now + 1,pos,mx);
    }
    int main(){
        n = read(),m = read();
        for(int i = 1;i <= m;i++)edges[i].u = read(),edges[i].v = read(),edges[i].d = read();
        sort(edges + 1,edges + 1 + m);
        s.init();
        lass = s;
        for(int i = 1;i <= m + 1;i++){
            if(edges[i].d != edges[i - 1].d){
                for(int i = 1;i <= n;i++)s.f[i] = s.find(s.f[i]);
                cnt = 0;
                dfs(last,1,i - 1);
                ans = (ans * cnt) % mod;
                last = i;
                lass = s;
                num = 0;
            }
            int x = s.find(edges[i].u),y = s.find(edges[i].v);
            if(x == y)continue;
            num++;
            s.merge(x,y);
        }
        printf("%d
    ",s.sz == 1 ? ans : 0);
        return 0;
    }
    
  • 相关阅读:
    xadmin进行全局配置(修改模块名为中文以及其他自定义的操作步骤)
    xadmin邮箱验证码 标题 EmailVerifyRecord object
    Django源码安装xadmin报错Apps aren't loaded yet.
    python虚拟环境virtualenv下安装MySQL-python(1.2.3)
    Pycharm界面的子窗口不见了,怎么办?
    MySQL-python终于安装成功了
    mysql-python 安装错误: Cannot open include file: 'config-win.h': No such file or directory
    配凑法
    双连不等式
    求参数的取值范围
  • 原文地址:https://www.cnblogs.com/colazcy/p/13538387.html
Copyright © 2011-2022 走看看