zoukankan      html  css  js  c++  java
  • BZOJ 1016 JSOI2008 最小生成树计数

    1016: [JSOI2008]最小生成树计数

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 6643  Solved: 2711
    [Submit][Status][Discuss]

    Description

      现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的
    最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生
    成树可能很多,所以你只需要输出方案数对31011的模就可以了。

    Input

      第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整
    数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,0
    00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

    Output

      输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

    Sample Input

    4 6
    1 2 1
    1 3 1
    1 4 1
    2 3 2
    2 4 1
    3 4 1

    Sample Output

    8

    HINT

    Source

    根据kruskal算法的基础是贪心,我们可以得出,不同的最小生成树的边权序列是一样的

    我们先做出kruskal得出最终的边权序列,然后逐个枚举每个边权有多少种不同的组成方法

    最后乘法原理乘起来即可,要注意使用并查集的时候不要带路径压缩,不要的话dfs就回溯不了了,但这样效率会变低

    不嫌麻烦的话写两个,我太懒了QAQ

    #include <bits/stdc++.h>
    #define ll long long
    #define inf 1000000
    #define eps 1e-7
    #define MOD 31011
    using namespace std;
    inline int read(){
        int x=0;int 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;
    }
    const int MAXN=1e6+10;
    struct node{
        int x,y,v;
    }e[MAXN];
    struct edge{
        int l,r,v;
    }a[MAXN];
    int f[MAXN],cnt,tot,sum;
    inline int find(int x){
        return x==f[x]?x:find(f[x]);
    }
    inline bool mycmp(node n,node m){
        return n.v<m.v;
    }
    inline void dfs(int st,int now,int k){
        if(now==a[st].r+1){
            if(k==a[st].v) sum++;
            return;
        }
        int fx=find(e[now].x);int fy=find(e[now].y);
        if(fx!=fy){
            f[fx]=fy;
            dfs(st,now+1,k+1);
            f[fx]=fx;f[fy]=fy;
        }
        dfs(st,now+1,k);
    }
    int main(){
        int n=read();int m=read();
        for(int i=1;i<=m;i++){
            e[i].x=read();e[i].y=read();e[i].v=read();
        }
        for(int i=1;i<=n;i++) f[i]=i;
        sort(e+1,e+m+1,mycmp);
        for(int i=1;i<=m;i++){
            if(e[i].v!=e[i-1].v){
                a[++cnt].l=i;a[cnt-1].r=i-1;
            }
            int fx=find(e[i].x);int fy=find(e[i].y);
            if(fx!=fy){
                a[cnt].v++;f[fx]=fy;tot++;
            }
        }
        a[cnt].r=m;
        for(int i=1;i<=n;i++) f[i]=i;
        if(tot!=n-1){
           cout<<0<<endl;return 0;
        }
        int ans=1;
        for(int i=1;i<=cnt;i++){
            sum=0;
            dfs(i,a[i].l,0);
            ans*=sum;
            ans%=MOD;
            for(int j=a[i].l;j<=a[i].r;j++){
                f[find(e[j].x)]=find(e[j].y);
            }
        } 
        cout<<ans<<endl;
        return 0;
    }
    

      

  • 相关阅读:
    【小白入门教程】3 分钟搞明白直播中拖动不准的问题
    如何在直播中解决黑屏、花屏、闪屏问题 | 直播疑难杂症排查
    骑兵变步兵?10 分钟搞明白如何在直播中去马赛克
    实现高性能纠删码引擎 | 纠删码技术详解(下)
    傅里叶分析之掐死教程(完整版)
    Python & 机器学习之项目实践
    LightGBM 调参方法(具体操作)
    模型调参:分步骤的提升模型的精度
    QQ的孤独
    python 机器学习中模型评估和调参
  • 原文地址:https://www.cnblogs.com/something-for-nothing/p/8093471.html
Copyright © 2011-2022 走看看