zoukankan      html  css  js  c++  java
  • BZOJ 1016--[JSOI2008]最小生成树计数(kruskal&搜索)

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

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 7429  Solved: 3098
    [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
     

    题目链接:

        http://www.lydsy.com/JudgeOnline/problem.php?id=1016 

    Solution

      首先可以发现在不同的最小生成树中,同权值的边的数量是一样的。。

      于是可以将每种权值的边的贡献分开算,然后用乘法原理就可以了。。

      对于某一种颜色,直接爆搜。。。感觉复杂度好像不太对。。。但是过了。。。

      算了反正都不知道多久之前写的了。。。

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define M 1010
    #define mod 31011
    using namespace std;
    int n,m,cnt,tot;
    int f[M],w[M],sum[M];
    bool c[M];
    struct edge{
        int l,r,w;
    }e[M],a[M];
    bool cmp(edge p,edge q){return p.w<q.w;}
    int find(int x){
        if(f[x]==x) return f[x];
        return find(f[x]);
    }
    void RE(){for(int i=1;i<=n;i++) f[i]=i;}
    void dfs(int x,int now,int k){
        if(now==a[x].r+1){
            if(k==a[x].w)tot++;
            return;
        }
        int xx=find(e[now].l),yy=find(e[now].r);
        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(){
        int ans=1;
        cnt=0;tot=0;
        int xx,yy;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&e[i].l,&e[i].r,&e[i].w);
        sort(e+1,e+1+m,cmp);
        RE();
        for(int i=1;i<=m;i++){
            if(e[i].w!=e[i-1].w){a[cnt].r=i-1;cnt++;a[cnt].l=i;}
            xx=find(e[i].l);yy=find(e[i].r);
            if(xx!=yy){f[xx]=yy;a[cnt].w++;tot++;}
        }
        a[cnt].r=m;
        if(tot+1!=n){printf("0
    ");return 0;}
        RE();
        for(int i=1;i<=cnt;i++){
            tot=0;
            dfs(i,a[i].l,0);
            ans=(ans*tot)%mod;
            for(int j=a[i].l;j<=a[i].r;j++){
                xx=find(e[j].l);yy=find(e[j].r);
                if(xx!=yy) f[xx]=yy;
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    

      

      

    This passage is made by Iscream-2001.

  • 相关阅读:
    aspcms产品详情页调取相关产品
    构造函数中返回一个对象对结果有什么影响
    跨域的几种方法及案例代码
    localStorage兼容方案
    H5 拖放事件详解
    由作用域安全的构造函数想到的
    valueOf和toString的区别
    网页布局--自适应
    【MongoDB系列】简介、安装、基本操作命令
    【JavaWeb】之Servlet
  • 原文地址:https://www.cnblogs.com/Yuigahama/p/9671568.html
Copyright © 2011-2022 走看看