• BZOJ1016 最小生成树计数


     

    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
     
     
    正解:克鲁斯卡尔最小生成树+搜索
    解题报告:
      今天考场上考了一道这个题目,我居然没看出来就是一道求最小生成树个数的裸题。。。
      说起来还是挺水的,就是有许多性质还掌握的不够熟练。不同的最小生成树方案,每种权值的边的数量是确定的,每种权值的边的作用是确定的。所以每种权值看作一个集合,这个集合若想对最终结果产生贡献,即是最小生成树,需要选取的边数是固定的。

      排序以后先做一遍最小生成树,得出每种权值的边使用的数量x

      然后对于每一种权值的边搜索,得出每一种权值的边选择方案。就是枚举某条边选不选,暴力搜索是否可行。(因为题目说同种权值不超过10,所以指数级大暴力不虚)

      最后乘法原理,每一步的方案数相乘。

     
     
      1 //It is made by jump~
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <ctime>
      9 #include <vector>
     10 #include <queue>
     11 #include <map>
     12 #include <set>
     13 #ifdef WIN32   
     14 #define OT "%I64d"
     15 #else
     16 #define OT "%lld"
     17 #endif
     18 using namespace std;
     19 typedef long long LL;
     20 const int MAXN = 211;
     21 const int MAXM = 10011;
     22 const int MOD = 31011;
     23 int n,m;
     24 int first[MAXN],next[MAXM],to[MAXM];
     25 int cnt;
     26 int father[MAXN];
     27 int ans,lin;
     28 
     29 struct build{
     30     int l,r,cnt;
     31 }a[MAXM];
     32 
     33 struct edge{
     34     int x,y,z;
     35 }e[MAXM];
     36 
     37 inline int getint()
     38 {
     39        int w=0,q=0;
     40        char c=getchar();
     41        while((c<'0' || c>'9') && c!='-') c=getchar();
     42        if (c=='-')  q=1, c=getchar();
     43        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
     44        return q ? -w : w;
     45 }
     46 
     47 inline bool cmp(edge q,edge qq){ return q.z<qq.z; }
     48 
     49 inline int find(int x){
     50     //不能路径压缩!!!
     51     if(father[x]!=x) return find(father[x]); //father[x]=find(father[x]);
     52     return father[x];
     53 }
     54 
     55 inline void dfs(int x,int now,int gong){
     56     if(now==a[x].r+1) {
     57     if(gong==a[x].cnt) lin++;//必须选指定的条数
     58     return ;
     59     }
     60     int r1=find(e[now].x),r2=find(e[now].y);
     61     if(r1!=r2) {//枚举选还是不选
     62     father[r1]=r2;
     63     dfs(x,now+1,gong+1);
     64     father[r1]=r1; father[r2]=r2;
     65     }
     66     dfs(x,now+1,gong);//不选
     67 }
     68 
     69 inline void solve(){
     70     n=getint(); m=getint();
     71     int x,y,z;
     72     for(int i=1;i<=m;i++) {
     73     x=getint(); y=getint(); z=getint();
     74     e[i].x=x; e[i].y=y; e[i].z=z;
     75     }
     76 
     77     sort(e+1,e+m+1,cmp);
     78 
     79     for(int i=1;i<=n;i++) father[i]=i;
     80 
     81     int gg=0;
     82     for(int i=1;i<=m;i++) {
     83     if(e[i].z!=e[i-1].z) { cnt++; a[cnt].l=i; a[cnt-1].r=i-1; }
     84     int r1=find(e[i].x),r2=find(e[i].y);
     85     if(r1!=r2) {
     86         father[r2]=r1;
     87         a[cnt].cnt++;
     88         gg++;
     89         //if(gg==n-1) break;
     90     }
     91     }
     92     a[cnt].r=m;
     93 
     94     if(gg!=n-1) { printf("0"); return ;  }
     95     for(int i=1;i<=n;i++) father[i]=i;
     96     
     97     ans=1;
     98     for(int i=1;i<=cnt;i++) {
     99     lin=0;
    100     dfs(i,a[i].l,0);
    101     ans*=lin; if(ans>=MOD) ans%=MOD;
    102 
    103     for(int j=a[i].l;j<=a[i].r;j++) {
    104         int r1=find(e[j].x),r2=find(e[j].y);
    105         if(r1!=r2) father[r2]=r1; 
    106     }
    107     }
    108 
    109     printf("%d",ans);
    110 }
    111 
    112 int main()
    113 {
    114   solve();
    115   return 0;
    116 }
  • 相关阅读:
    MHA自动切换流程
    手写源码之 简单实现on emit off
    手写源码 -- bind,call,aplly
    多维数组转化为一维数组
    electron+vue中使用nodeJs的fs模块以及上传文件
    制作海报
    vue中引入播放器(百度播放器和腾讯云播放器)
    webpack配置
    webpack
    css样式
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5575720.html
Copyright © 2020-2023  润新知