zoukankan      html  css  js  c++  java
  • 【Luogu】P4208最小生成树计数(状压乱搞)

      题目链接

      最小生成树有两个性质,两个性质都知道的话这题就变成码农题了。

      1、无论最小生成树长什么样,所有权值的边的数量是不变的。比如我有棵最小生成树有两条权值为2的边四条权值为1的边,那这个图的所有最小生成树都是两条权值为2的边四条权值为1的边。

      2、无论最小生成树长什么样,把边从小到大排序,某一权值的边连完后,联通块一定是固定的。

      这就提示了我们先求一遍最小生成树,得到生成树里每个权值的边都有几条,然后枚举权值,状压当前权值选的边集,看能不能把选出来的这些边都摁进森林里去。如果能的话该权值的连接方案数就+1.

      枚举完之后,因为第二条所以我们直接把所有该权值的边的两个端点合到一个并查集里就好了。

      最后乘法原理得到答案。

      

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    #include<cstdlib>
    #define maxn 10000
    #define mod 31011
    using namespace std;
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    struct Edge{
        int from,to,val;
    }edge[maxn],q[maxn],d[maxn];
    bool cmp(Edge a,Edge b){    return a.val<b.val;    }
    int head[maxn],num;
    inline void add(int from,int to,int val){
        edge[++num]=(Edge){head[from],to,val};
        head[from]=num;
    }
    
    bool vis[maxn];
    int sum[maxn];
    int w[maxn];
    int size;
    struct fus{
        int father[maxn];
        inline void clear(int n){    for(int i=1;i<=n;++i)    father[i]=i;    }
        int find(int x){
            if(father[x]!=x)    father[x]=find(father[x]);
            return father[x];
        }
        inline void unionn(int x,int y){
            x=find(x);    y=find(y);
            father[y]=x;
        }
    }c,r,right;
    
    inline int getlen(int x){
        int ans=0;
        while(x){
            if(x&1)    ans++;
            x>>=1;
        }
        return ans;
    }
    
    int ans[maxn];
    int pre[maxn];
    
    void copy(int x,int *a,int *b){    for(int i=1;i<=x;++i)    a[i]=b[i];}
    
    int main(){
        int n=read(),m=read();
        for(int i=1;i<=m;++i)    q[i]=(Edge){read(),read(),read()};
        c.clear(n);
        sort(q+1,q+m+1,cmp);
        int cnt=0,last=0,now=0;
        for(int i=1;i<=m;++i){
            //离散化 
            now=q[i].val;
            if(q[i].val==last)    q[i].val=size;
            else                 q[i].val=++size;
            last=now;
            
            int from=q[i].from,to=q[i].to;
            if(c.find(from)==c.find(to))    continue;
            c.unionn(from,to);
            vis[q[i].val]=1;
            sum[q[i].val]++;
            cnt++;
            if(cnt==n-1)    break;
        }
        if(cnt<n-1){
            printf("0");
            return 0;
        }
        c.clear(n);
        cnt=0;
        int maxval=0;
        for(int i=1;i<=m;++i)
            if(vis[q[i].val]){
                d[++cnt]=q[i];
                w[q[i].val]++;
                maxval=max(maxval,q[i].val);
            }
        last=0;
        for(int i=1;i<=maxval;++i){
            int Max=1<<w[d[last+1].val];
            copy(n,right.father,c.father);
            for(int j=0;j<Max;++j){
                if(getlen(j)!=sum[d[last+1].val])    continue;
                bool flag=0;
                copy(n,r.father,c.father);
                for(int k=0;(1<<k)<=j;++k)
                    if(j&(1<<k)){
                        int ret=(k+1)+last;
                        if(r.find(d[ret].from)==r.find(d[ret].to)){
                            flag=1;
                            break;
                        }
                        r.unionn(d[ret].from,d[ret].to);
                    }
                if(flag==0){
                    ans[d[last+1].val]++;
                    copy(n,right.father,r.father);
                }
            }
            copy(n,c.father,right.father);
            last+=w[d[last+1].val];
        }
        for(int i=1;i<=maxval;++i)
            if(w[i]){
                last=i;
                break;
            }
        for(int i=last;i<=maxval;++i){
            if(ans[i]&&i!=last){
                ans[i]=(ans[i]*ans[last])%mod;
                last=i;
            }
        }
        printf("%d
    ",ans[last]);
        return 0;
    }
  • 相关阅读:
    非对称加密-RSA公钥加密,私钥解密,私钥加签,公钥验签
    设置mysql数据库本地连接或外部可连接
    mysql自增长主键,删除数据后,将主键顺序重新排序
    非Service层和Controller层调用ssm框架中的方法
    DES加密算法(密文只有字符串和数字)java和android加密的结果一致(可放在url中)
    SpringBoot ajax Restful整合
    java中线程执行流程详解
    在 CSS 中直接引用 fontawesome 图标(附码表)
    C++内存管理~
    操作系统那些事儿
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8794817.html
Copyright © 2011-2022 走看看