定义:
最大团就是给你一个图,让你在这个图里面找到一个最大的子图,这个子图必须是全图,最大的子图就是这个图的最大团。
算法:
首先最大团是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;
}