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";
}