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

    思路

    刚看到的时候,因为 ((nleq 100)) ,所以想到了爆搜,但是这样做显然会 (TLE) ,所以我们手摸几组数据找找结论

    然后能发现一个结论:一张图上的不同最小生成树中,权值相等的边的个数是不变的

    小证明:用kruskal求最小生成树时,每一步都是最优的,如果有不同的最小生成树,则当前步的权值必然小于等于之前最小生成树当前步的选择。但是反证可得,如果有小于的话,此时的最小生成树就比之前的优了,和之前矛盾,所以权值相等的边的个数是不变的。

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    const int mod=31011;
    struct node{
        int from,to,w;
    }e[1010];
    struct kruskal{
        int l,r,v;
    }a[1010];//存i边的个数,l r是左右端点,v是i在最小生成树上的个数
    int n,m,f[110],ans,q[110],num,sum;
    
    int find(int x){return x==f[x]?x:find(f[x]);}
    //不能路径压缩!!!
    
    bool cmp(node a,node b){
        return a.w<b.w;
    }
    
    void dfs(int x,int now,int k)//x是你当前找的值 now是第几个边 k是你选了的个数
    {
        if(now==a[x].r+1){
            if(k==a[x].v) sum++;//保证和生成树所需的一样
            return ;
        }
        int xx=find(e[now].from),yy=find(e[now].to);
        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(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) f[i]=i;
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&e[i].from,&e[i].to,&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) num++,a[num].l=i,a[num-1].r=i-1;
            int xx=find(e[i].from),yy=find(e[i].to);
            if(xx!=yy) f[xx]=yy,a[num].v++,tot++;
        }//kruskal
        if(tot!=n-1){
            printf("0");
            return 0;
        }//如果构不成树,就可以输出0了
        a[num].r=m;
        ans=1;
        for(int i=1;i<=n;i++) f[i]=i;
        for(int i=1;i<=num;i++){
            sum=0;
            dfs(i,a[i].l,0);
            ans=(ans*sum)%mod;
            for(int j=a[i].l;j<=a[i].r;j++){
                int xx=find(e[j].from),yy=find(e[j].to);
                if(xx!=yy) f[xx]=yy;
            }//弄完一个后,连起来保证不为环
        }
        printf("%d",ans);
        return 0;
    }
    
  • 相关阅读:
    99乘法表-利用数组
    100以内素数
    99乘法表
    第6周小组作业:软件测试和评估
    第4周小组作业:WordCount优化
    第2周个人作业:WordCount
    博客阅读和思考
    第一个C#窗体应用程序开发总结-----单号单面法调整单操作程序
    实验十——一维数组的定义及引用
    实验九——基本数据类型存储及应用总结
  • 原文地址:https://www.cnblogs.com/jasony/p/13543213.html
Copyright © 2011-2022 走看看