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


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

    题意:

    思路:

    一个无向图所有的最小生成树中某种权值的边的数目均相同。

    引用一篇大牛的证明:

    我们证明以下定理:一个无向图所有的最小生成树中某种权值的边的数目均相同。

    开始时,每个点单独构成一个集合。

    首先只考虑权值最小的边,将它们全部添加进图中,并去掉环,由于是全部尝试添加,那么只要是用这种权值的边能够连通的点,最终就一定能在一个集合中。

    那么不管添加的是哪些边,最终形成的集合数都是一定的,且集合的划分情况一定相同。那么真正添加的边数也是相同的。因为每添加一条边集合的数目便减少1.

    那么权值第二小的边呢?我们将之间得到的集合每个集合都缩为一个点,那么权值第二小的边就变成了当前权值最小的边,也有上述的结论。

    因此每个阶段,添加的边数都是相同的。我们以权值划分阶段,那么也就意味着某种权值的边的数目是完全相同的。

    所以先用克鲁斯卡尔算法计算一遍最小生成树,统计每一权值的边组需要加几条边,最后暴搜,乘法原理相乘即可。注意,要判断无法连通的情况。

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<sstream>
      6 #include<vector>
      7 #include<stack>
      8 #include<queue>
      9 #include<cmath>
     10 #include<map>
     11 #include<set>
     12 using namespace std;
     13 typedef long long ll;
     14 typedef pair<int,ll> pll;
     15 const int INF = 0x3f3f3f3f;
     16 const int maxn=10000+5;
     17 const int mod=31011;
     18 
     19 struct node
     20 {
     21     int u,v,w;
     22 }e[10*maxn];
     23 
     24 struct node2
     25 {
     26     int l,r;
     27     int c;
     28 }a[maxn];
     29 
     30 int n, m;
     31 int sum;
     32 int cnt,tot;
     33 int p[maxn];
     34 
     35 bool cmp(node a, node b)
     36 {
     37     return a.w<b.w;
     38 }
     39 
     40 int find(int x)
     41 {
     42     return x==p[x]?x:find(p[x]);
     43 }
     44 
     45 void dfs(int cur, int num ,int pos)
     46 {
     47     if(pos>a[cur].r)
     48     {
     49         if(num==a[cur].c) sum++;
     50         return;
     51     }
     52     int x=find(e[pos].u);
     53     int y=find(e[pos].v);
     54     if(x!=y)
     55     {
     56         p[x]=y;
     57         dfs(cur,num+1,pos+1);
     58         p[x]=x;
     59     }
     60     dfs(cur,num,pos+1);
     61 }
     62 
     63 int main()
     64 {
     65     //freopen("in.txt","r",stdin);
     66     while(~scanf("%d%d",&n,&m))
     67     {
     68         for(int i=1;i<=n;i++) p[i]=i;
     69         for(int i=1;i<=m;i++)
     70             scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
     71 
     72         sort(e+1,e+m+1,cmp);
     73         cnt=0; tot=0;
     74         for(int i=1;i<=m;i++)
     75         {
     76             if(e[i].w!=e[i-1].w)
     77             {
     78                 a[++cnt].l=i;
     79                 a[cnt-1].r=i-1;
     80                 a[cnt].c=0;
     81             }
     82             int x=find(e[i].u);
     83             int y=find(e[i].v);
     84             if(x!=y)
     85             {
     86                 p[x]=y;
     87                 a[cnt].c++;
     88                 tot++;
     89             }
     90         }
     91         a[cnt].r=m;
     92         
     93         if(tot!=n-1)  //连不起来的情况
     94         {
     95             printf("0
    ");
     96             continue;
     97         }
     98         
     99 
    100         for(int i=1;i<=n;i++)   p[i]=i;
    101         int ans=1;
    102         for(int i=1;i<=cnt;i++)
    103         {
    104             sum=0;
    105             dfs(i,0,a[i].l);
    106             ans=(ans*sum)%mod;
    107             for(int j=a[i].l;j<=a[i].r;j++)
    108             {
    109                 int x=find(e[j].u);
    110                 int y=find(e[j].v);
    111                 if(x!=y) p[x]=y;
    112             }
    113         }
    114         printf("%d
    ",ans);
    115     }
    116     return 0;
    117 }
  • 相关阅读:
    201671010112 第十四周 Swing用户界面组件
    201671010112 第十二周
    201671010112 第十二周—— “如何在eclipse中重定向标准输入到文件?”整理方案
    201671010112 第十一周
    201671010112 第十周
    201671010112 第九周
    201671010112 第八周
    201671010112 第六周
    面向对象的程序设计课程进度
    201671010111 2016-2017-2《面向对象的程序设计》 java学习总结
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/7348721.html
Copyright © 2020-2023  润新知