2 条题解

  • 0
    @ 2025-10-8 16:49:35

    一般图最大团

    讲解:(转载于https://blog.csdn.net/SparkFucker/article/details/83051133

    Bron-Kerbosch算法

    该算法本质也是DFS。引入三个集合,all集合,some集合,none集合,其中some集合代表待检查且可能能加入团的节点,none集合代表已经检查过且我们认为不能加入团的节点,all则是检查过并且我们认为能加入最大团的节点,当some集合和none集合都为空的时候,all集合即为我们需要求的极大团。每次我们检查some集合里的一个节点,并把它加入all集合,那么可能加入待检查序列的就是它自己的邻接点(毕竟要保证团内所有点都有边相连),和some集合做一个交集,none集合同样和邻接点们作交集,以保证some和none里面的点和all里的点都有边相连。把当前检查点从all里拿出来以后就放入none里面,再从some集合的下一个开始检查。some集合为空的时候就没有可以加入all集合的点了,some集合为空且none集合不为空的时候就代表none集合里面的点放进all集合团会更大(之前检查过这种情况),所以一定要两个集合都为空才行。

    这里还要介绍一种优化方法,因为不加这个优化可能连板子题都会TLE。如果我们要从some里选一个点pivot加入到all里的话,它的邻接点势必会因为和some作交集而留在some里待检查,在下一层DFS里势必会被检查,所以没有必要在检查pivot的这一层里再以它们为起点去检查,这会导致重复。选pivot的时候也可以以度数的大小选度数最大的点,这样能减少的检查次数也最多。

    //一般图的最大独立集=一般图补图的最大团 
    #include<cstdio>
    #include<cstring>
    • 0
      @ 2025-10-8 16:49:19

      一般图最大团

      讲解:(转载于https://blog.csdn.net/SparkFucker/article/details/83051133

      Bron-Kerbosch算法

      该算法本质也是DFS。引入三个集合,all集合,some集合,none集合,其中some集合代表待检查且可能能加入团的节点,none集合代表已经检查过且我们认为不能加入团的节点,all则是检查过并且我们认为能加入最大团的节点,当some集合和none集合都为空的时候,all集合即为我们需要求的极大团。每次我们检查some集合里的一个节点,并把它加入all集合,那么可能加入待检查序列的就是它自己的邻接点(毕竟要保证团内所有点都有边相连),和some集合做一个交集,none集合同样和邻接点们作交集,以保证some和none里面的点和all里的点都有边相连。把当前检查点从all里拿出来以后就放入none里面,再从some集合的下一个开始检查。some集合为空的时候就没有可以加入all集合的点了,some集合为空且none集合不为空的时候就代表none集合里面的点放进all集合团会更大(之前检查过这种情况),所以一定要两个集合都为空才行。

      这里还要介绍一种优化方法,因为不加这个优化可能连板子题都会TLE。如果我们要从some里选一个点pivot加入到all里的话,它的邻接点势必会因为和some作交集而留在some里待检查,在下一层DFS里势必会被检查,所以没有必要在检查pivot的这一层里再以它们为起点去检查,这会导致重复。选pivot的时候也可以以度数的大小选度数最大的点,这样能减少的检查次数也最多。
      ---------------------
      作者:SparkFucker
      来源:CSDN
      原文:https://blog.csdn.net/SparkFucker/article/details/83051133
      版权声明:本文为博主原创文章,转载请附上博文链接!

      代码(码风很丑):

      //一般图的最大独立集=一般图补图的最大团 
      #include<cstdio>
      #include<cstring>
      #include<algorithm>
      using  namespace  std;
      inline  void  getx(int  &x)
      {
       x=0;char  c=getchar();
       while(c>'9'  ||  c<'0')c=getchar();
       while(c<='9'  &&  c>='0')x=(x<<3)+(x<<1)+(c^48),c=getchar();
      }
      bool  ma[410][410];/*反向建图,True没边,False有边*/
      int  some[410][410]/*可能成为下一个在团中的点*/,none[410][410]/*已经找过的且与目前团中所有点有边的点*/,all[410][410]/*团中点,目前没用*/;
      int  n,m,ans;
      int  deg[410];//每个点的在反图的度数 
      inline  bool  cmp(int  x,int  y){return  deg[x]>deg[y];}//度数排序 
      void  BK(int  pos,int  al,int  so,int  no)
      {
       if(al+so<=ans)return  ;//剪枝优化 
       if(so==0  &&  no==0/*判重*/)
       {
        ans=al;
        return  ;
       }
       int  pi=0;//优化 
       if(so)//all可继承上一层 
       {
        pi=some[pos][1];//因为已经按度数排序了 
        for(int  i=1;i<=al;i++)all[pos+1][i]=all[pos][i];
       }
       for(int  i=1;i<=so;i++)
       {
        int  nxt=some[pos][i];//目前放进团中的点 
        if(!ma[pi][nxt])continue;//优化 
        int  nno=0,nso=0;//下一层的some和none 
        for(int  j=1;j<=so;j++)//在some找与这个点有边相连的点 
        {
         if(!ma[nxt][some[pos][j]])some[pos+1][++nso]=some[pos][j];
        }
        for(int  j=1;j<=no;j++)//在none找与这个点有边相连的点 
        {
         if(!ma[nxt][none[pos][j]])none[pos+1][++nno]=none[pos][j];
        }
        all[pos+1][al+1]=nxt;
        BK(pos+1,al+1,nso,nno);
        some[pos][i]=0;none[pos][++no]=nxt;//把这个点踢到none里面 
       }
      }
      int  main()
      {
       getx(n);getx(m);
       for(int  i=1;i<=n;i++)some[0][i]=i,deg[i]=n-1,ma[i][i]=ma[0][i]=ma[i][0]=True;//初始化 
       for(int  i=1;i<=m;i++)
       {
        int  x,y;getx(x);getx(y);//快读 
        ma[x][y]=ma[y][x]=True;deg[x]--;deg[y]--;
       }
       sort(some[0]+1,some[0]+n+1,cmp);
       ans=0;BK(0,0,n,0);
       printf("%d\n",ans);
       return  0;
      }


      • 1

      *【一般图:最大独立集】一般图最大独立集[模板](未解决)

      信息

      ID
      324
      时间
      1000ms
      内存
      128MiB
      难度
      6
      标签
      递交数
      68
      已通过
      19
      上传者