集训队专题(5.1)1007 All Friends

来源:互联网 发布:dj混音软件 编辑:程序博客网 时间:2024/06/05 17:41

All Friends

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other)
Total Submission(s) : 69   Accepted Submission(s) : 22
Problem 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. <br> <br>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. <br> <br>
 

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 41 23 42 34 5
 

Sample Output
4
 

Source
PKU

题意:给出n个人之间的朋友关系,让我们求出极大团的数量。这里小编我先介绍一下概念问题。

1.团:表示N 个点的集合,这N个点彼此两两连接,既有N(N-1)/2条边。

2.极大团:无法作为其他团的子团的团。

从概念的角度讲,极大团和最大团是有区别的,而且不难发现,最大团就是定点数最多的极大团。让我们回到这个题目,首先我们得理解题意是让我们求极大团,而不是最大团……样例也很坑啊,很容易就想成是最大团。

知道了是求极大团后,让我们来看看求极大团数量的算法:Bron-Kerbosch算法。

有关Bron-Kerbosch算法的资料在网上能找到的并不多,在维基上能找到一篇关于Bron-Kerbosch算法的详细的介绍,但……那是英文文献,相信很多和小编一样同为英语渣的童鞋有种无比蛋疼的感觉(TT),这里小编结合自己的理解详细解释一下Bron-Kerbosch算法的运行过程。

首先,我们需要用到三个数组,all,some,none,三个数组分别的作用是记录加入团的点集,即将进行搜索的点集,和之后一步搜索不用的点集。可能只看到这里读者会感觉莫名其妙,不知道这三个数组具体怎么用,接下来,小编就开始详细的介绍这三个数组。

还是先看一下DFS的代码:

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

在这段DFS中,an,sn,nn,分别表示all,some,none,三个数组中的点数。在搜索之前的初始化为all,none两个数组为0,而some包含所有点,第一步是把所有点都作为根节点开始一一展开搜索,由于我们搜索的是无向图,一个极大团的点若我们搜索的方向不同,很可能会有记录重复的现象发生(比如1.2.3.4.5是一个极大团,如果我们没有方向的搜索没有方向的限制,那我们搜索到1.2.3.4.5是一个,2.1.3.4.5又是一个,就有记录重复的现象发生),所以我们对点的搜索都以从小编号点搜索到大编号点的顺序进行,但又会有一个问题,若以大编号点作为根节点的话,可能搜索到的极大团实际上不是极大团(比如1.2.3.4.5是一个极大团,但是我们以2为根节点进行搜索的时候如果不考虑1的话,我们可能就会把2.3.4.5也当做一个极大团),所以我们需要借助数组none,我们把因为已经搜索过,而不以之作为新的枝点又和新的枝点有连接关系的点加入none,以便能够判断,而all这个数组,每次我们都把新加入的作为枝点的点加入进行记录,当我们得出一个极大团的时候,我们可以通过输出得到这个极大团中的点,当然这题由于并没有要求对极大团的点进行记录,所以这里我们不加这个数组也没有问题。我们对极大团的判定条件是当sn和nn同时都为0的时候,便可以得到是极大团。可能有童鞋又不明白这个判定条件了,仔细想想,如果加入团的点每一个点都是互相连接,没有其他的点可以再搜索(sn == 0),又没有和之前的点有连接关系的没有作为枝点的点存在(nn == 0)的时候,就可以得到这个团是极大团了。讲了这么多希望读者能有所思考和收获,以下是这题的AC代码:

#include <cstdio>#include <cstring>const int maxn = 130;int N,M,a[maxn],g[maxn][maxn];void input(){memset(g,0,sizeof(g));for(int i=0; i<M; i++){int x,y;scanf("%d%d",&x,&y);g[x][y] = g[y][x] = 1;}}int S,all[maxn][maxn],some[maxn][maxn],none[maxn][maxn];void dfs(int d,int an,int sn,int nn){if(S > 1000) return ;if(sn == 0 && nn == 0) S++;int u = sn>0? some[d][0] : none[d][0];for(int i=0; i<sn; i++){int v = some[d][i];if(g[u][v]) continue;int tsn = 0,tnn = 0;for(int j=0; j<an; j++) all[d+1][j] = all[d][j];all[d+1][an] = v;for(int j=0; j<sn; j++)if(g[v][some[d][j]])some[d+1][tsn++] = some[d][j];for(int j=0; j<nn; j++)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;}}void process(){S = 0;for(int i=0; i<N; i++)some[0][i] = i+1;dfs(0, 0, N, 0);if(S > 1000) printf("Too many maximal sets of friends.\n");else printf("%d\n",S);}int main(){while(scanf("%d%d",&N,&M)!=EOF){input();process();}return 0;}



0 0
原创粉丝点击