給定無向圖G=(V,E),其中V是非空集合,稱爲頂點集;E是V中元素構成的無序二元組的集合,稱爲邊集,無向圖中的邊均是頂點的無序對,無序對常用圓括號“( )”表示。
如果U V,且對任意兩個頂點u,v∈U有(u,v)∈E,則稱U是G的完全子圖。G的完全子圖U是G的團。G的最大團是指G的最大完全子圖。
如果U∈V且對任意u,v∈U有(u,v)不屬於E,則稱U是G的空子圖。G的空子圖U是G的獨立集當且僅當U不包含在G的更大的空子圖中。G的最大獨立集是G中所含頂點數最多的獨立集。
對於任一無向圖G=(V,E),其補圖G'=(V',E')定義爲:V'=V,且(u,v)∈E'當且僅當(u,v)∉E。
如果U是G的完全子圖,則它也是G'的空子圖,反之亦然。因此,G的團與G'的獨立集之間存在一一對應的關係。特殊地,U是G的最大團當且僅當U是G'的最大獨立集。
通俗點講就是在一個無向圖中找出一個點數最多的完全圖。
最大獨立集 = 補圖的最大團
最大團 = 補圖的最大獨立集
鏈接:hdu - 1530
最大團模板:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1005;
/*
最大團 = 補圖G的最大獨立集數
———>最大獨立集數 = 補圖G'的最大團
*/
//最大團模板
bool mp[maxn][maxn];//mp爲圖的鄰接表(從1開始)
int ans, cnt[maxn], group[maxn], n, m, vis[maxn];//ans表示最大團,cnt[maxn]表示當前最大團的節點數,group[maxn]用以尋找一個最大團集合
bool dfs(int u, int pos) {
//u爲當從前頂點開始深搜,pos爲深搜深度(即當前深搜樹所在第幾層的位置)
for(int i = u + 1; i <= n; i++) {
int j;
//按遞增順序枚舉頂點
if(cnt[i] + pos <= ans) //剪枝
return 0;
if(mp[u][i]) {
// 與目前團中元素比較,取 Non-N(i)
for(j = 0; j < pos; j++)
if(!mp[i][vis[j]])
break;
if(j == pos) {
// 若爲空,則皆與 i 相鄰,則此時將i加入到 最大團中
vis[pos] = i;//深搜層次也就是最大團的頂點數目,vis[pos] = i表示當前第pos小的最大團元素爲i(因爲是按增順序枚舉頂點 )
if(dfs(i, pos + 1))
return 1;
}
}
}
if(pos > ans) {
for(int i = 0; i < pos; i++)
group[i] = vis[i]; // 更新最大團元素
ans = pos;
return 1;
}
return 0;
}
void maxclique() {//求最大團
ans = -1;
for(int i = n; i > 0; i--) {
vis[0] = i;
dfs(i, 1);
cnt[i] = ans;
}
}
int main()
{
while(~scanf("%d", &n)) {
if(n == 0) break;
memset(mp, 0, sizeof(mp));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &mp[i][j]);
maxclique();//求最大團
if(ans < 0)
ans = 0;//ans表示最大團
printf("%d\n", ans);
/*for(int i = 0; i < ans; i++)
printf( i == 0 ? "%d" : " %d", group[i]); //group[maxn]用以尋找一個最大團集合
if( ans > 0 ) puts("");*/
}
}