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

    P4208 [JSOI2008]最小生成树计数


    讲课的时候提到了这个妙极了的思想,于是就把这题做了。

    有个结论:相同边权的边集不论怎么选,对最小生成树的贡献都相同(选的数量都会相同,而且连完之后图的连通性也会相同)

    所以可以把不同边权的边分开来看,答案就是每种边权的方案之积。

    于是就可以愉快地暴力了:

    1. 从小到大枚举边权;
    2. 拿出这个边权的所有边,并算出要连多少条边,以及连接这些边会连通哪些点;
    3. 暴力枚举选哪些边,加入方案里;
    4. 最后把现在通的集合缩起来。

    复杂度上界是(O(m 2^{10} n)),然而远远达不到,因为(2^{10})最大也就是(C ^{5}_{10}),而且因为要缩点,n也不会一直是n。

    emmm还有,注意判断无解情况

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cctype>
    using namespace std;
    typedef int mmp;
    #define vd void
    #define rg register
    #define il inline
    #define sta static
    il int gi(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    namespace YYB{
        int n,m;
        struct edge{int u,v,w;}yyb[1001];
        int operator <(const edge&a,const edge&b){return a.w<b.w;}
        int fa[101];
        il int find(int*fa,int x){return fa[x]==x?x:fa[x]=find(fa,fa[x]);}
        il bool Union(int*fa,int x,int y){
            x=find(fa,x),y=find(fa,y);
            if(x>y)swap(x,y);
            if(x!=y){fa[y]=x;return 1;}
            return 0;
        }
        il vd solve(){
            n=gi(),m=gi();
            for(rg int i=1;i<=m;++i)yyb[i].u=gi(),yyb[i].v=gi(),yyb[i].w=gi();
            sort(yyb+1,yyb+m+1);
            for(rg int i=1;i<=n;++i)fa[i]=i;
            int ans=1;
            for(rg int i=1;i<=m;++i){
                int j=i;while(yyb[j+1].w==yyb[i].w)++j;
                for(rg int s=i;s<=j;++s)yyb[s].u=find(fa,yyb[s].u),yyb[s].v=find(fa,yyb[s].v);
                int fafa[101],tot=0;
                for(rg int s=1;s<=n;++s)fafa[s]=s;
                for(rg int s=i;s<=j;++s)if(Union(fafa,yyb[s].u,yyb[s].v))++tot;
                int res=0;
                for(rg int s=0;s<1<<(j-i+1);++s){
                    int cnt=0;for(rg int p=s;p;p-=p&-p)++cnt;
                    if(cnt!=tot)continue;
                    for(rg int q=1;q<=n;++q)fafa[q]=q;
                    int tot_=0;
                    for(rg int q=i;q<=j;++q)
                        if(s&(1<<q-i))
                            if(Union(fafa,yyb[q].u,yyb[q].v))++tot_;
                    if(tot_==tot)++res;
                }
                for(rg int s=i;s<=j;++s)Union(fa,yyb[s].u,yyb[s].v);
                ans=ans*res%31011;
                i=j;
            }
            for(rg int i=1;i<=n;++i)if(find(fa,i)!=1)ans=0;
            printf("%d
    ",ans);
        }
    }
    mmp main(){
        //freopen("bzoj_1016.in","r",stdin);
        //freopen("bzoj_1016.out","w",stdout);
        YYB::solve();
        return 0;
    }
    
  • 相关阅读:
    evernote100个做笔记的好方法
    平衡二叉树的调整模版
    晨间日记的奇迹
    hdu 2952 Counting Sheep
    hdu 1535 Invitation Cards
    poj 3259 Wormholes(spfa)
    poj 2263 Heavy Cargo(floyd)
    poj 3268 Silver Cow Party(SPFA)
    hdu 1690 Bus System
    hdu 3631 Shortest Path(Floyd)
  • 原文地址:https://www.cnblogs.com/xzz_233/p/8656490.html
Copyright © 2011-2022 走看看