• BZOJ1016 最小生成树计数


      题面描述

      最小生成树计数

      给定一个n个点、m条边的无向图,求其最小生成树的个数。相同边权的边不会超过10条。

      思维难度:提高+;代码难度:提高+;

      题解:

      先给出两个引理:

      1.克鲁斯卡尔求最小生成数实际上是分成很多个阶段的,你可以感受到:很多边权相同的边因为排序顺序不同,导致它们被访问的顺序不同。但每处理完一个边权相同的边集,当前图的一些性质(连通块数、边数、代价数)是一样的,并不会因为同边权集中的边的排序顺序改变而改变。换句话说,图的本质可能会变,但它的“表现”是不变的。

      2.不同的阶段产生的边,对于每棵最小生成树,是恒定的,且每个阶段在保证正确的如何选择,对后面的选择没有影响。统计答案时,应该使用乘法原理。

      那么我们接下来有两种方法:Matrix Tree 或者 爆搜2333

      注意到题面中写的“相同边权的边不超过10条”,直接指数级爆搜选不选就可以了。并查集时不能用路径压缩,因为你要有撤销功能。

      提交次数:2次 第一次是因为没删调试代码。B站不显示错误输出真是好坑啊。

      这题启示我们:省选题也有指数级爆搜的舞台(ohhh)。

      

    #include    <iostream>
    #include    <cstdio>
    #include    <cstdlib>
    #include    <algorithm>
    #include    <vector>
    #include    <cstring>
    #include    <queue>
    #define LL long long int
    #define ls (x << 1)
    #define rs (x << 1 | 1)
    using namespace std;
    const int Mod = 31011;
    struct Node{int u,v,w;}E[Mod];
    int n,m,Ans,flag,fa[Mod],vis[Mod],ans;
    int gi()
    {
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    LL gl()
    {
      LL x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    bool cmp(const Node &a,const Node &b){return a.w<b.w;}
    int find(int x){return fa[x]==x?x:find(fa[x]);}
    void dfs(int dep,int ch,int nu,int ed,int num)
    {
      if(nu==num){ans++;return;}
      if(dep==ed)return;
      dfs(dep+1,0,nu,ed,num);
      if(find(E[dep+1].u)!=find(E[dep+1].v))
        {
          int x=find(E[dep+1].v);
          fa[x]=find(E[dep+1].u);
          dfs(dep+1,1,nu+1,ed,num);
          fa[x]=x;
        }
    }
    int solve(int l,int r)
    {
      int num=0,fat[110];ans=0;
      for(int i=1;i<=n;++i)fat[i]=fa[i];
      for(int i=l;i<=r;++i)
        if(find(E[i].u)!=find(E[i].v))
          num++,fa[find(E[i].v)]=find(E[i].u);
      for(int i=1;i<=n;++i)swap(fa[i],fat[i]);
      dfs(l-1,0,0,r,num);
      for(int i=1;i<=n;++i)fa[i]=fat[i];
      return ans;
    }
    void work()
    {
      sort(E+1,E+m+1,cmp);
      for(int i=1;i<=n;++i)fa[i]=i;
      for(int i=1,num=0;i<=m;++i)
        {
          int x=find(E[i].u),y=find(E[i].v);
          if(x!=y)fa[y]=x,num++;
          if(num==n-1)break;
          if(i==m)Ans=0;
        }
      for(int i=1;i<=n;++i)fa[i]=i;
      for(int i=1,last=1;i<=m;++i)
        {
          if(E[i].w!=E[last].w)
    	{
    	  Ans*=solve(last,i-1);
    	  Ans%=Mod;last=i;
    	}
          if(i==m){Ans*=solve(last,m);}
        }
    }
    int main()
    {
      n=gi();m=gi();Ans=1;
      for(int i=1;i<=m;++i)
        E[i].u=gi(),E[i].v=gi(),E[i].w=gi();
      work();printf("%d",Ans%Mod);
      return 0;
    }
    

      

  • 相关阅读:
    (JS+CSS)实现图片放大效果
    PowerDesigner(数据建模)使用大全
    可输入的下拉框(简易实现)
    MVC 验证码实现( 简易版)
    http程序接口、调用(最入门级,文末附Demo)
    【BZOJ】3730: 震波
    【HDU】HDU5664 Lady CA and the graph
    【AtCoder】AGC016
    【AtCoder】ARC076
    【AtCoder】AGC032
  • 原文地址:https://www.cnblogs.com/fenghaoran/p/6594939.html
Copyright © 2020-2023  润新知