PAT 1142
C++
版
1.题意
给出一个图的信息。判断给出的顶点是否能够组成一个maximal clique
。其中
-
clique
的判断依据是:给出的顶点集合中任意两个顶点都是联通的。 -
maximal clique
的判断依据则是:给出的顶点集合中任意两个顶点都是联通的。如果从图中再加入任何一个节点,则会导致节点不再连通。
2.分析
本题的关键是如何将顶点的边信息进行有效的存储。最起初的时候,我使用的方式是:
- 使用set将某个顶点的所有边信息完全存储,例如:如果顶点1与2,3,4有边。则得到的结果就是
ver[1] = 2,3,4
。
但是使用set 组成的二维数组的一个弊端就是:对于判断是否是maixmal clique
是很艰难的。因为首先你需要从不同的ver[i]
中找出公共的元素;然后再判断公共元素是否包含所有的查询节点。
所以应该采用的方式是: -
使用一个二维数组作为邻接矩阵。保存所有的节点的边信息。然后可以判断是否是一个
clique
。对于判断是否是一个maximal clique
,则直接使用当前的查询顶点集和所有的图节点进行遍历,查找其edge[a][0]
~edge[a][l-1]
是否都为1,如果都为1,则说明不是Maximal Clique
。
3.代码
这里暂不给出代码。过两天再更新。【更新代码见文末】
4.测试用例
8 10
5 6
7 8
6 4
3 6
4 5
2 3
8 2
2 7
5 3
3 4
6
4 5 4 3 6
3 2 8 7
2 2 3
1 1
3 4 3 6
3 3 2 1
5.执行结果
6.总结
- 【许久未看数据结构,连一些很基础的东西都忘掉了(╥╯^╰╥)】
- 采取什么样的的数据结构对于解题是有很大影响的。
3.代码
代码如下:
#include<cstdio>
#include<iostream>
#define maxn 205
using namespace std;
//存储边信息
int edge[maxn][maxn];
int main(){
int Nv,Ne;
cin >> Nv >> Ne;
int i,j,k;
int ver1,ver2;
for(i = 0;i< Ne;i++){
cin>> ver1 >> ver2;
edge[ver1][ver2] = 1;
edge[ver2][ver1] = 1;
}
int M,K;
int query[maxn];
int flag;
cin >> M;
for(i = 0; i< M;i++){
cin >>K;
flag = 0;//init value
for(j = 0;j< K;j++){
cin >> query[j];
}
//双层遍历,查看所有的顶点是否都是联通的
for(j = 0; j< K; j++){
for(k = j+1; k< K; k++){
if(edge[query[j]][query[k]] != 1){//说明这两个顶点之间没有边
flag = 1;
break;
}
}
if(flag == 1){
cout << "Not a Clique"<<"\n";
break;
}
}
if(j == K){//说明所有的节点都已经遍历结束了,这时候再判断是否是Maximal
for(j = 1; j <= Nv; j++){ //注意j的下标从1开始,而不是从0 开始
for(k = 0;k < K;k++){
if(edge[j][query[k]] != 1) break;
}
if(k == K){
cout <<"Not Maximal"<<"\n";
break;
}
}
if(j > Nv){//说明是一个Maximal Clique
cout <<"Yes"<<"\n";
}
}
}
}
这里有如下几个地方需要注意:
for(j = 1; j <= Nv; j++){
...
}
这里的j
的下标从1开始,而不是从0 开始。因为顶点的下标是从1开始的。而不是0。相应的,下面的判断就应该修改成:
if(j > Nv){//说明是一个Maximal Clique
cout <<"Yes"<<"\n";
}