POJ - 2989 All Friends 极大团

Time Limit: 1000MS Memory Limit: 65536KB 64bit IO Format: %lld & %llu

Status

Description

Sociologists are interested in the phenomenon of "friendship". To study this property, they analyze various groups of people. For each two persons in such a group they determine whether they are friends (it is assumed that this relation is symmetric). The sociologists are mostly interested in the sets of friends. The set S of people is the set of friends if every two persons in S are friends. However, studying the sets of friends turns out to be quite complicated, since there are too many such sets. Therefore, they concentrate just on the maximal sets of friends. A set of friends S is maximal if every person that does not belong to S is not a friend with someone in S.

Your task is to determine the number of maximal sets of friends in each group. In case this number exceeds 1 000, you just need to report this -- such a group is too complicated to study.

Input

The input consists of several instances, separated by single empty lines.

The first line of each instance consists of two integers 1 ≤ n ≤ 128 and m -- number of persons in the group and number of friendship relations. Each of m following lines consists of two integers ai and bi (1 ≤ ai, bi ≤ n). This means that persons ai and bi (ai ≠ bi) are friends. Each such relationship is described at most once.

Output

The output for each instance consists of a single line containing the number of maximal sets of friends in the described group, or string "Too many maximal sets of friends." in case this number is greater than 1 000.

Sample Input

5 4
1 2
3 4
2 3
4 5

Sample Output

4


题意:给出n个人,其中m对朋友,求最大团数量(就是在团中的人互为朋友,不在团中的人与某些在团中的人不互为朋友,在本题中人数不要求最多)



题解:要用Bron–Kerbosch算法。找最大团,我们设了三个数组:all, some, none,  分别表示的是已经选了的点,还没动的点,不要的点(避免重复,实际上就是判重)。

算法的思想是将some中的点逐步加入all和none中,当我们将一个点v放入all中时,把和它有连接的点的点集

交上当前的some点集,就是下一个的some点集,同样,none也是一样的,这样保证了团中的点互相连接


主要思路(http://blog.csdn.net/dy0607/article/details/52800556)

优化:设key = some[1],则仅当key与v不为朋友时,才需要枚举v,因为此时与v相关的必定已被搜过(与None同理,但可以大大加速)

    BronKerbosch(All, Some, None):  
        if Some and None are both empty:  
            report All as a maximal clique //所有点已选完,且没有不能选的点,累加答案  
        for each vertex v in Some: //枚举Some中的每一个元素  
            BronKerbosch1(All ⋃ {v}, Some ⋂ N(v), None ⋂ N(v))   
            //将v加入All,显然只有与v为朋友的人才能作为备选,None中也只有与v为朋友的才会对接下来造成影响  
            Some := Some - {v} //已经搜过,在Some中删除,加入None  
            None := None ⋃ {v}  



主要代码(dfs)

void dfs(int d, int an, int sn, int nn){
	if(!sn && !nn) S++;//已经搜到了,与所选点全部有连接的点以全部放入all中
	
	int u = some[d][1]; 
	For(i, 1, sn){
		int v = some[d][i];
		if(G[u][v]) continue;//优化,只要取与当前已经搜过的点没有连接的点就可以了,因为它们肯定已经被处理过了
		int tsn = 0, tnn = 0;
	
		For(j, 1, an) all[d+1][j] = all[d][j];
		all[d+1][an+1] = v; //将点v放入all中
		
		For(j, 1, sn)
		  if(G[v][some[d][j]]) some[d+1][++tsn] = some[d][j];
		For(j, 1, nn)
		  if(G[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; //从some中取出v,放入none(判重)
	}
}

本题代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>

using namespace std;

#define MAXN (150+5)
#define INF 0x3f3f3f3f
#define Set(a, v) memset(a, v, sizeof(a))
#define For(i, a, b) for(int i = (a); i <= (int)(b); i++)

bool G[MAXN][MAXN];
int n, m, S, all[MAXN][MAXN], some[MAXN][MAXN], none[MAXN][MAXN];

void init(){
	Set(G, 0);
}

void dfs(int d, int an, int sn, int nn){
	if(!sn && !nn) S++;
	if(S > 1000) return;
	
	int u = some[d][1];
	For(i, 1, sn){
		int v = some[d][i];
		if(G[u][v]) continue;
		int tsn = 0, tnn = 0;
	
		For(j, 1, an) all[d+1][j] = all[d][j];
		all[d+1][an+1] = v;
		
		For(j, 1, sn)
		  if(G[v][some[d][j]]) some[d+1][++tsn] = some[d][j];
		For(j, 1, nn)
		  if(G[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;
	}
}

int main(){
	freopen("test.in", "r", stdin);
	freopen("test.out", "w", stdout);
	
	while(scanf("%d%d", &n, &m) != EOF){
		init();
			
		For(i, 1, m){
			int u, v;
			scanf("%d%d", &u, &v);
			G[u][v] = G[v][u] = true;
		}
		For(i, 1, n) some[0][i] = i;
		
		S = 0;
		dfs(0, 0, n, 0);
		if(S <= 1000) printf("%d\n", S);
		else printf("Too many maximal sets of friends.\n");
	}
	
	return 0;
}


  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值