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

    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

    Solution

    这题目,鬼畜至极。。。看了题解,又发现是矩阵树。。然后经过非常合理的判断,这个题目有一个非常友好的性质——具有相同权值的边不会超过10条。这样就使暴力搜索这种做法成为了可能的做法。

    YY一下, 我们可以知道对于我们已经求出的一棵最小生成树,其中每种权值的边的数量就已经是确定的了。那么我们枚举每一种权值的边,判断它有几种方案可行即可。又由于刚才那个美妙的性质,我们每一种边权的最大枚举次数最多是1024。

    Code

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <iostream>
    #include <cstdlib>
    #include <cmath>
    #include <string>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    #define re register
    #define mo 31011
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    #define ms(arr) memset(arr, 0, sizeof(arr))
    const int inf = 0x3f3f3f3f;
    struct po
    {
        int x,y,l;
    };
    po a[1010];
    struct tt
    {
        int l,r,v;
    } p[1010];
    int n,m,t,cnt,num,f[1001],sum,tot;
    inline int read()
    {
        int x=0,c=1;
        char ch=' ';
        while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
        while(ch=='-') c*=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
        return x*c;
    }
    inline bool cmp(po a,po b)
    {
        return a.l<b.l;
    }
    inline int find(int x)
    {
        return x==f[x]?x:find(f[x]);
    }
    void dfs(int x,int now,int k)
    {
        if(now==p[x].r+1){
            if(k==p[x].v) sum++;
            return;
        }
        int r1=find(a[now].x),r2=find(a[now].y);
        if(r1!=r2){
            f[r1]=r2;
            dfs(x,now+1,k+1);
            f[r1]=r1;f[r2]=r2;
        }
        dfs(x,now+1,k);
    }
    int main() 
    {
        n=read();m=read();
        for(re int i=1;i<=m;i++)
            a[i].x=read(),a[i].y=read(),a[i].l=read();
        for(re int i=1;i<=n;i++) f[i]=i;
        sort(a+1,a+m+1,cmp);
        for(re int i=1;i<=m;i++){
            if(a[i].l!=a[i-1].l) cnt++,p[cnt].l=i,p[cnt-1].r=i-1;
            int r1=find(a[i].x),r2=find(a[i].y);
            if(r1!=r2) f[r1]=r2,p[cnt].v++,tot++;
        }
        if(tot!=n-1) {
            cout<<0;
            return 0;
        }
        p[cnt].r=m;
        int ans=1;
        for(re int i=1;i<=n;i++) f[i]=i;
        for(re int i=1;i<=cnt;i++){
            sum=0;
            dfs(i,p[i].l,0);
            ans=(ans*sum)%mo;
            for(re int j=p[i].l;j<=p[i].r;j++){
                int r1=find(a[j].x),r2=find(a[j].y);
                if(r1!=r2) f[r1]=r2;
            }
        }
        cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    752.打开转盘锁
    733. 图像渲染
    704.二分查找
    leetcode 87 Scramble String
    找实习总结
    leetcode 44 Wildcard Matching
    Linux,网络编程接口记录
    leetcode 172 Factorial Trailing Zeroes
    leetcode 168 Excel Sheet Column Title
    leetcode 65 Valid Number
  • 原文地址:https://www.cnblogs.com/victorique/p/9175013.html
Copyright © 2011-2022 走看看