基础知识
-
团:无向图的完全子图,图的最大全连通分量
完全图:完全图是一个简单的无向图,其中每对不同的顶点之间都恰连有一条边相连。 -
极大团:如果一个团不被其他任一团所包含,即它不是其他任一团的真子集,则称该团为图G的极大团(maximal clique)。
-
最大团就是就是结点数最多的极大团。
-
独立集: 独立集是指图 G 中两两互不相邻的顶点构成的集合。
-
最大独立集:图 G 中顶点数最多的那个独立集。
-
最大团的点的数目 = 补图中最大独立集点的数目。
比如:1-2,1-3,1-4,2-3。补图为1-4,2-4,于是补图中{1,2,3}构成了最大独立集,点数为3,即也是原图的最大团的点的数目。
延申【二分图中的一些知识点】
在二分图中,最大独立集= 最小边覆盖 = 总点数- 最大匹配。
在二分图中,最小点覆盖 = 最大匹配数。
最大匹配数:最大匹配的匹配的边数
- 点覆盖:对于图G=(V,E)中的一个点覆盖,是一个点集合S⊆V使得G中每一条边至少有一个端点在S中。
- 边覆盖:是一类覆盖,指一类边子集。图的一个边子集,使该图上每一节点都与这个边子集中的一条边关联,只有含孤立点的图没有边覆盖。
最小点覆盖:求最少的点集,使得每一条边 至少有1个端点在这个点集中。
最小边覆盖:求最少的边集,使得他们覆盖所有的点,并且每一个点只被一条边覆盖。
-
二分图匹配基础+算法【pick】:http://www.renfei.org/blog/bipartite-matching.html
-
二分图概念、知识点比较丰富:https://blog.csdn.net/qq_41730082/article/details/81456611
-
匈牙利算法接地气理解:
https://blog.csdn.net/u013384984/article/details/90718287
https://blog.csdn.net/sunny_hun/article/details/80627351 -
这个算法挺全的:https://blog.csdn.net/ling_wang/article/details/79830980
模板
好多,就先上这两种就好
模板1:Bron-Kerbosch
【取自链接https://www.jianshu.com/p/437bd6936dad】
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 130;
bool mp[maxn][maxn];
int some[maxn][maxn], none[maxn][maxn], all[maxn][maxn];
//分别是P集合,X集合,R集合
/*
P集合记录的是可能还能加入的点
X集合记录的是已经加入过某个极大团的点
R集合记录的是当前极大团中已经加入的点。
*/
int n, m, ans;
void dfs(int d, int an, int sn, int nn)
{//d为搜索深度,an、sn、nn分别为all(R)、some(P)、none(X)集合中顶点数,
if(!sn && !nn) {
//ans=ans<an?an:ans; //最大团的顶点数
ans++;//极大团的数目
return;
}
int u = some[d][0]; //选取Pivot结点 这里每次会选择邻居结点多的那个结点当作Pivot,
for(int i = 0; i < sn; ++i)
{
int v = some[d][i];
if(mp[u][v]) continue;
//v就是u结点本身,或者v不是u的邻居结点则可继续下一次的dfs
for(int j = 0; j < an; ++j)
{
all[d+1][j] = all[d][j];
}
all[d+1][an] = v;
int tsn = 0, tnn = 0;
for(int j = 0; j < sn; ++j) if(mp[v][some[d][j]]) some[d+1][tsn++] = some[d][j];
for(int j = 0; j < nn; ++j) if(mp[v][none[d][j]]) none[d+1][tnn++] = none[d][j];
dfs(d+1, an+1, tsn, tnn);
some[d][i] = 0, none[d][nn++] = v;
if(ans > 1000) return;
}
}
int work(){
ans = 0;
for(int i = 0; i < n; ++i) some[1][i] = i+1;
dfs(1, 0, n, 0);
return ans;
}
int main(){
while(~scanf("%d %d", &n, &m))
{
memset(mp, 0, sizeof mp);
for(int i = 1; i <= m; ++i)
{
int u, v;
scanf("%d %d", &u, &v);
mp[u][v] = mp[v][u] = 1;
}
int tmp = work();
if(tmp > 1000) puts("Too many maximal sets of friends.");
else printf("%d\n", tmp);
}
return 0;
}
模板2
【取自链接https://www.cnblogs.com/yefeng1627/archive/2013/03/31/2991592.html】
#include<cstdio>
#include<cstring>
#define N 1010
bool flag[N], a[N][N];
int ans, cnt[N], group[N], n, vis[N];
bool dfs( int u, int pos ){
int i, j;
for( i = u+1; i <= n; i++){
if( cnt[i]+pos <= ans ) return 0;
if( a[u][i] ){
// 与目前团中元素比较,取 Non-N(i)
for( j = 0; j < pos; j++ ) if( !a[i][ vis[j] ] ) break;
if( j == pos ){ // 若为空,则皆与 i 相邻,则此时将i加入
vis[pos] = i;
if( dfs( i, pos+1 ) ) return 1;
}
}
}
if( pos > ans ){
for( 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;
}
}
练手
https://www.cnblogs.com/zhj5chengfeng/p/3224092.html
https://www.jianshu.com/p/437bd6936dad
https://www.cnblogs.com/yefeng1627/archive/2013/03/31/2991592.html
https://www.cnblogs.com/zhj5chengfeng/p/3224092.html
https://www.jianshu.com/p/dabbc78471d7
https://www.cnblogs.com/adelalove/p/8653441.html
http://www.renfei.org/blog/bipartite-matching.html
https://blog.csdn.net/qq_41730082/article/details/81456611
https://blog.csdn.net/u013384984/article/details/90718287
https://blog.csdn.net/sunny_hun/article/details/80627351
https://blog.csdn.net/ling_wang/article/details/79830980