• 【最小生成树】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 }
  • 相关阅读:
    网络流模型之二分图匹配问题
    省选测试8
    省选测试9
    省选测试7
    省选测试6
    网络流最大流、最小割学习笔记
    kruskal重构树学习笔记
    省选测试5
    Python 打包成exe 方式
    JQuery
  • 原文地址:https://www.cnblogs.com/xkui/p/4565265.html
Copyright © 2020-2023  润新知