图论---极大团(POJ 2989,Hdu 1530)

1、极大团:

一个图G = (V,E),要求选取一个子图,这个图中的任意两个点都能相互到达,当这个子图的顶点数最多时,

这个图就是图G的极大团。

 

2、求解方法:

Born_Kerbosch算法:

(1)规定三个集合:

R:极大团中所包含的顶点;

P:未被匹配,还有可能加入极大团的点;

X:已经被其他极大团匹配过的点,就是已经计数过的点,用于判断重复的极大团;

 

(2)然后我们找到这三个集合之间的关系:

如果集合P,X都为空集,此时,R一定是一个最大团;

因为如果集合P不为空集,说明P中还有点可以进入极大团;

如果集合X不为空集,说明X中还有已经计数过的点,这些点必然与R中的点相邻(之前判断过),

所以这些点也有可能进入极大团。

所以可以用dfs搜索所有的点,然后不断更新集合P,X,将新的点加入集合R,求出极大团。

 

(3)对dfs的详解&优化:

因为每次选取的点都是集合P与集合X的交集Z,所以可以从Z中任意选取一点u,

递归查找包含u的极大团,然后选取与u不相邻的点v,因为每次选取v就相当于选取了所有与v相邻的点,

然后递归查找到包含点v的极大团,所以要求u,v两点之间不相邻,这样可以避免重复查找。

递归查找极大团时,每次找到一个新的节点就要更新集合P,集合X,

所以更新集合P = 集合P中所有与u相连的点;

更新集合X  = 集合X中所有与u相连的点;

如果找到集合P = 空集,集合X = 空集,就说明找到了一个极大团,结束查找。

 

 3、题目:

说了这么多还是上代码吧:

 

poj  2989 (查找极大团的数量)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1005;
int R[maxn][maxn],P[maxn][maxn],X[maxn][maxn],mp[maxn][maxn],n,m,ans;
bool dfs(int d,int rn,int pn,int xn){
	if(pn==0&&xn==0){
		ans++;
		if(ans>1000) return 1; //判断是否到达1000的最大值,是否用进行回溯统计下一个极大团 
		return 0;
	}
	int u = P[d][0];//取出P中的一个点 
	for(int i=0;i<pn;i++){
		int v = P[d][i];
		if(mp[u][v]==1) continue;//找与u不相连的点,因为相连的点都在一个极大团里 
		for(int j=0;j<rn;j++)
		R[d+1][j] = R[d][j]; 
		R[d+1][rn] = v; //将新点加入极大团 
		int tpn = 0,txn = 0;
		for(int j=0;j<pn;j++)
		if(mp[v][P[d][j]]) P[d+1][tpn++] = P[d][j]; //更新集合P,记录P与v的交集 
		for(int j=0;j<xn;j++)
		if(mp[v][X[d][j]]) X[d+1][txn++] = X[d][j]; //更新集合X,记录X与v的交集 
		if(dfs(d+1,rn+1,tpn,txn))
			return 1;
		P[d][i] = 0;X[d][xn++] = v; //删除原来的v的记录,将完成极大团的点加入X集合 
	}
	return 0;
}
int main(void){
	while(~scanf("%d%d",&n,&m)){
		memset(mp,0,sizeof(mp));
		for(int i=1;i<=m;i++){
			int x,y;scanf("%d%d",&x,&y);
			mp[x][y] = mp[y][x] = 1;
		}
		ans = 0;
		for(int i=0;i<n;i++) P[0][i] = i+1;
		dfs(0,0,n,0);
		if(ans>1000) printf("Too many maximal sets of friends.\n");
		else printf("%d\n",ans);
	}
	return 0;
}

 

 

Hdu 1530 (查找极大团最多有多少个节点)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 55;
int mp[maxn][maxn],P[maxn][maxn],R[maxn][maxn],X[maxn][maxn],n,ans;
void dfs(int d,int rn,int pn,int xn){
	if(!pn&&!xn){
		ans = max(ans,rn);
		return ;
	}
	int u = P[d][0];
	for(int i=0;i<pn;i++){
		int v = P[d][i];
		if(mp[u][v]==1) continue;
		for(int j=0;j<rn;j++)
		R[d+1][j] = R[d][j];
		R[d+1][rn] = v;
		int tpn = 0,txn = 0;
		for(int j=0;j<pn;j++)
		if(mp[v][P[d][j]]==1)
			P[d+1][tpn++] = P[d][j];
		for(int j=0;j<xn;j++)
		if(mp[v][X[d][j]]==1)
			X[d+1][txn++] = X[d][j];
		dfs(d+1,rn+1,tpn,txn);
		P[d][i] = 0;X[d][xn++] = v;
	}
}
int main(void){
	while(~scanf("%d",&n)&&n){
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++) scanf("%d",&mp[i][j]);
		ans = 0;
		for(int i=0;i<n;i++) P[0][i] = i+1;
		dfs(0,0,n,0);
		printf("%d\n",ans);
	}
	return 0;
}

 

4、参考文章:

文章一

文章二

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用C++实现极大问题的示例代码: ```c++ #include <iostream> #include <vector> #include <algorithm> using namespace std; const int MAXN = 100; // 最大顶点数 int n, m; int g[MAXN][MAXN]; // 无向图邻接矩阵 vector<int> clique; // 记录最大 bool dfs(int p, vector<int>& candidate) { if (candidate.size() == 0) { // 所有候选点都已处理 if (clique.size() < p) { // 更新最大 clique.clear(); for (int i = 1; i <= p; i++) { clique.push_back(g[i][0]); } } return true; } if (p + candidate.size() <= clique.size()) { return false; // 剪枝:候选点数量不足以组成更大的 } int u = candidate.back(); candidate.pop_back(); vector<int> new_candidate; for (int i = 0; i < candidate.size(); i++) { int v = candidate[i]; if (g[u][v]) { new_candidate.push_back(v); // u与v相邻,加入新的候选点 } } if (dfs(p + 1, new_candidate)) { return true; } candidate.push_back(u); // u不在最大中 return dfs(p, candidate); } void max_clique() { vector<int> candidate; for (int i = n; i >= 1; i--) { candidate.clear(); for (int j = i + 1; j <= n; j++) { if (g[i][j]) { candidate.push_back(j); } } dfs(1, candidate); } } int main() { cin >> n >> m; for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; g[u][v] = g[v][u] = 1; } max_clique(); cout << "Max clique size: " << clique.size() << endl; cout << "Max clique vertices: "; for (int i = 0; i < clique.size(); i++) { cout << clique[i] << " "; } cout << endl; return 0; } ``` 该代码首先使用邻接矩阵表示无向图,然后使用深度优先搜索算法递归地找到最大。在搜索的过程中,使用一个候选点集合来记录当前可以选择的点,每次从中选出一个点加入当前中,然后更新候选点集合,继续搜索。如果候选点集合为空,则当前为最大,更新最大。如果当前大小加上候选点集合大小仍然小于最大的大小,则剪枝,直接返回。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值