✍个人博客:https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
📚专栏地址:PAT题解集合
📝原题地址:题目详情 - 1142 Maximal Clique (pintia.cn)
🔑中文翻译:最大团
📣专栏定位:为想考甲级PAT的小伙伴整理常考算法题解,祝大家都能取得满分!
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
1142 Maximal Clique
A clique is a subset of vertices of an undirected graph such that every two distinct vertices in the clique are adjacent. A maximal clique is a clique that cannot be extended by including one more adjacent vertex. (Quoted from https://en.wikipedia.org/wiki/Clique_(graph_theory))
Now it is your job to judge if a given subset of vertices can form a maximal clique.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers Nv (≤ 200), the number of vertices in the graph, and Ne, the number of undirected edges. Then Ne lines follow, each gives a pair of vertices of an edge. The vertices are numbered from 1 to Nv.
After the graph, there is another positive integer M (≤ 100). Then M lines of query follow, each first gives a positive number K (≤ Nv), then followed by a sequence of K distinct vertices. All the numbers in a line are separated by a space.
Output Specification:
For each of the M queries, print in a line
Yes
if the given subset of vertices can form a maximal clique; or if it is a clique but not a maximal clique, printNot Maximal
; or if it is not a clique at all, printNot a Clique
.Sample Input:
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
Sample Output:
Yes Yes Yes Yes Not Maximal Not a Clique
题意
在一个无向图中,如果一个顶点子集满足子集内的任意两个不同顶点之间都是相连的,那么这个顶点子集就被称为一个团。
如果一个团不能通过加入某个新的顶点来扩展成一个更大的团,那么该团就被称为最大团。
现在,你需要判断给定顶点子集能否构成一个最大团。
举个例子,下图中 [1,2,3,4]
就是该图的最大团,而 5
不在其中是因为 5
与 3
和 2
没有边。
思路
- 这题用邻接矩阵来存储每一条边。
- 每次询问时用数组
vers
去存储每个点值,并用cnt
记录点数。然后先判判断该子集是否是团,如果是团再进一步判断是否为最大团。- 判断是否是团,只需判断子集中每个点之间是否都存在边。
- 判断是否为最大团,需要先用一个数组
st
来标记子集中有哪些点,然后再遍历不是子集中的点,再去判断这些点是否和子集中的每个点都存在一条边,只要能找到一个这种点,就说明不是最大团。
- 根据判断结果,输出对应语句。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 210;
int g[N][N];
int vers[N];
bool st[N];
int n, m;
//判断是不是团
bool check_clique(int cnt)
{
//判断每个点之间是否都存在边
for (int i = 0; i < cnt; i++)
for (int j = 0; j < i; j++)
if (!g[vers[i]][vers[j]])
return false;
return true;
}
//判断是不是最大团
bool check_maximum(int cnt)
{
memset(st, 0, sizeof st); //初始化
//先将子集中的点进行标记
for (int i = 0; i < cnt; i++) st[vers[i]] = true;
//然后遍历不在子集中的点
for (int i = 1; i <= n; i++)
if (!st[i])
{
//判断该点是否与子集中的所有点都有边
bool success = true;
for (int j = 0; j < cnt; j++)
if (!g[i][vers[j]])
{
//只要子集中有一个点与其没边,该点就不属于该团
success = false;
break;
}
//根据遍历结果判断是否为最大团
if (success) return false;
}
return true;
}
int main()
{
cin >> n >> m;
//记录每条边
for (int i = 0; i < m; i++)
{
int a, b;
cin >> a >> b;
g[a][b] = g[b][a] = true;
}
//开始查询
int k;
cin >> k;
while (k--)
{
int cnt;
cin >> cnt;
for (int i = 0; i < cnt; i++) cin >> vers[i]; //输入子集
//判断是不是团
if (check_clique(cnt))
{
//判断是不是最大团
if (check_maximum(cnt)) puts("Yes");
else puts("Not Maximal");
}
else puts("Not a Clique");
}
return 0;
}