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

    Description

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

    Solution

    把所有边权相同的视为边组,每一组边组在最小生成树的条数是固定的,对连通性的贡献也是固定的。(证明可以看http://www.cnblogs.com/Fatedayt/archive/2012/05/10/2494877.html)

    在确定贡献之后,爆搜每一组边即可。

    用矩阵树也可以做,然而我还不会QwQ。

    Code

    并查集不能路径压缩,不然就不好回溯时还原了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=1e3+5,mod=31011;
     5 
     6 struct edge{
     7     int u,v,w;
     8     bool operator<(const edge&a)
     9         const{return w<a.w;}
    10 }e[maxn];
    11 int l[maxn],r[maxn],t[maxn],cnt;
    12 int p[maxn];
    13 int find(int x){return p[x]==x?x:find(p[x]);}
    14 int n,m;
    15 
    16 int ret;
    17 void dfs(int i,int j,int k){
    18     if(j==r[i]+1){
    19         if(k==t[i]) ret++,ret%=mod;
    20         return;
    21     }
    22     int x=find(e[j].u),y=find(e[j].v);
    23     if(x!=y){
    24         p[x]=y;
    25         dfs(i,j+1,k+1);
    26         p[x]=x;
    27     }
    28     dfs(i,j+1,k);
    29 }
    30 
    31 int main(){
    32     scanf("%d%d",&n,&m);
    33     for(int i=1;i<=m;i++)
    34         scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    35     sort(e+1,e+m+1);
    36     
    37     int tot=0;
    38     for(int i=1;i<=n;i++) p[i]=i;
    39     for(int i=1;i<=m;i++){
    40         if(i==1||e[i].w!=e[i-1].w){
    41             r[cnt]=i-1;
    42             l[++cnt]=i;
    43         }
    44         int x=find(e[i].u),y=find(e[i].v);
    45         if(x!=y){
    46             t[cnt]++;
    47             tot++;
    48             p[x]=y;
    49         }
    50     }
    51     r[cnt]=m;
    52     
    53     
    54     if(tot!=n-1){
    55         printf("0
    ");
    56         return 0;
    57     }
    58     for(int i=1;i<=n;i++) p[i]=i;
    59     
    60     int ans=1;
    61     for(int i=1;i<=cnt;i++){
    62         ret=0;
    63         dfs(i,l[i],0);
    64         ans=ans*ret,ans%=mod;
    65         for(int j=l[i];j<=r[i];j++){
    66             int x=find(e[j].u),y=find(e[j].v);
    67             if(x!=y) p[x]=y;
    68         }    
    69     }
    70     printf("%d",ans);
    71     return 0;
    72 }
  • 相关阅读:
    codevs 2632 非常好友
    codevs 1213 解的个数
    codevs 2751 军训分批
    codevs 1519 过路费
    codevs 1503 愚蠢的宠物
    codevs 2639 约会计划
    codevs 3369 膜拜
    codevs 3135 River Hopscotch
    数论模板
    JXOJ 9.7 NOIP 放松模拟赛 总结
  • 原文地址:https://www.cnblogs.com/xkui/p/4565265.html
Copyright © 2011-2022 走看看