对最大团的理解

定义: 
    最大团就是给你一个图,让你在这个图里面找到一个最大的子图,这个子图必须是全图,最大的子图就是这个图的最大团。


算法:
      首先最大团是NP问题,没有什么非常快的方法去解决,现在可以用搜索+剪枝去尽可能的快速处理最大团问题,其中一个很重要的剪枝就是如果当前集合的顶点数+剩下所有的点<当前全局的最优答案,那么直接return,不然搜下去也没意义,我们要枚举每一个团,找到最大的那个,对于当前点,如果满足要求(和当前团所有点都有连边)那么他可以加入团或者放弃,如果满足要求,直接放弃,一直枚举,更新最优就行了。
接着补充一下,经过做3585的那个二分最大团发现自己写的模板各种超时,超时到蛋疼,最后学了下dp优化的,然后就过了,dp优化的理解是这样的,对于dp优化首先我们要知道如果这样的写法


枚举第一个点的时候for(int i = n - 1 ;i >= 1 ;i --)
DFS里面跑的时候for(int i = x + 1 ;i <= n ;i ++)
这样就导致每次DFS是比上次增加了一个节点,对于当前点的本次搜索索要面临的点都已经被枚举过了,然后当前这个点加入如果是"有效"的,那么他肯定是之前的某一个团+1,如果当前的这个点要走的点+要走的那个点的之前最大团还是没有当前全局答案大,那么就没有必要遍历了,直接就continue就行了。


//*******************************
最大团:图G的顶点的子集D,若D中任意两点相邻,且含有的顶点数最大,则D为最大团。
        因此若u,v在最大团中,则u,v必有边相连
        一个有N个顶点的最大团,边数为N*(N-1)/2
求最大团是NP问题,常用的方法是DP优化+ DFS
 
与之相关的概念是最大独立集:
独立集是指图的顶点集的一个子集,该子集的导出子图不含边。
一个图中包含顶点数目最多的独立集称为最大独立集。
所以最大独立子集=图的补图的最大团
//***********************************


自己写的一个模板(容易超时)


#include<stdio.h>


#define N 60


int map[N][N] ,n;
int now[N] ,Ans;


bool ok(int sum ,int to)
{
   for(int i = 1 ;i <= sum ;i ++)
   if(!map[now[i]][to]) return 0;
   return 1;
}


void DFS(int to ,int sum ,int node)
{
   if(Ans < sum) Ans = sum;
   if(sum + n - node < Ans) return;
   for(int i = to + 1 ;i <= n ;i ++)
   if(ok(sum ,i)) 
   {
      now[sum + 1] = i;
      DFS(i ,sum + 1 ,node + 1);
   }
}


int main ()
{
   int i ,j;
   while(~scanf("%d" ,&n) && n)
   {
      for(i = 1 ;i <= n ;i ++)
      for(j = 1 ;j <= n ;j ++)
      scanf("%d" ,&map[i][j]);
      Ans = 0;
      for(i = 1 ;i <= n ;i ++)
      {
         now[1] = i;
         DFS(i ,1 ,1);
      }
      printf("%d " ,Ans);
   }
   return 0;
}


dp优化的(目前比较快的)
#include<stdio.h>


#define N 60


int map[N][N];
int dp[N] ,now[N];
int n ,Ans;


void DFS(int x ,int sum)
{
   if(sum > Ans) Ans = sum;
   
   int able = 0;
   int tnow[N];
   for(int i = x + 1 ;i <= n ;i ++)
   {
      tnow[i] = now[i];
      if(now[i]) able ++;
   }
   if(able + sum <= Ans) return;
   
   for(int i = x + 1 ;i <= n ;i ++)
   {
      if(!tnow[i]) continue;
      if(dp[i] + sum <= Ans) return;
      for(int j = x + 1 ;j <= n ;j ++)
      now[j] = tnow[j] & map[i][j];
      DFS(i ,sum + 1);
   }
}


int Max_Tuan()
{
   Ans = dp[n] = 1;
   for(int i = n - 1 ;i >= 1 ;i --)
   {
      for(int j = 1 ;j <= n ;j ++)
      now[j] = map[i][j];
      DFS(i ,1);
      dp[i] = Ans;
   }
   return Ans;
}


int main ()
{
   int i ,j;
   while(~scanf("%d" ,&n) && n)
   {
      for(i = 1 ;i <= n ;i ++)
      for(j = 1 ;j <= n ;j ++)
      scanf("%d" ,&map[i][j]);
      printf("%d " ,Max_Tuan());
   }
   return 0;
}
   
   








      
原文地址:https://www.cnblogs.com/csnd/p/12062888.html