题意解析
团:子集内任意两个顶点都有边相连。
非团:有顶点但是没有边相连。
最大团:是团且不能再加入其他顶点使其扩展为更大的团。
非最大团:是团且可以加入其他顶点使其扩展为更大的团。
判断是否是最大团
首先判断子集是否是一个团。如果一个子集内任意两点之间都有边相连,那么就说该子集是一个团。
然后判断该团是否是一个最大团。如果存在一个不在该团内的点且该点与该团内任意顶点都有一条边,那么就说这个团不是最大团。
样例模拟
这是题目提供的图:
第一个询问
子集为{5,3,4,6},该子集内任意两点之间存在一条边,是一个团。且不存在团外一点与团内所有点都存在一条边,因此该团是一个最大团:
输出"yes":
第二个询问
子集为{2,8,7},该子集内任意两点之间存在一条边,是一个团,且不存在团外一点与团内所有点都存在一条边,因此该团是一个最大团:
输出"yes":
第三个询问
子集为{2,3},该子集内任意两点之间存在一条边,是一个团,且不存在团外一点与团内所有点都存在一条边,因此该团是一个最大团:
输出"yes":
第四个询问
子集为{1},子集内任意两点之间有一条边(自己与自己连),是团。
且没有团外任意一点与团内所有点存在一条边,是最大团。
输出"yes":
第五个询问:
子集为{4,3,6},该子集满足子集内任意两顶点之间存在一条边,因此是一个团。
另外我们可以发现团外一点5与该团内任意顶点之间都有一条边,因此该团不是一个最大团。
输出"Not Maximal":
第六个询问:
子集为{1,2,3},因为该子集内不满足任意两点之间存在一条边(3到1没有边),所以该子集不是一个团。
输出"Not a Clique":
code
#include<bits/stdc++.h>
using namespace std;
int n, m,k;
const int N = 210;
int g[N][N];
bool st[N];
int ver[N];
//判断是否是一个团
//方法:判断团内任意两个定点之间是否都存在一条边
bool is_clique(int cnt) {
for (int i = 0; i < cnt; i++)
for (int j = 0; j < i; j++)
if (!g[ver[i]][ver[j]])return false;
return true;
}
//判断是否为一个最大团
//方法:判断团外是否存在一个点与团内任意顶点存在一条边
bool is_max_clique(int cnt)
{
memset(st,false,sizeof st); //初始化每个点为没走过
//看看能否加入一个新边
for (int i = 0; i < cnt; i++)st[ver[i]] = true; //每个顶点都初始化为true
//枚举每一个点
for (int i = 1; i <= n; i++)
{
bool res = true;
if (!st[i]) //没有被访问过的话
{
res = true;
for (int j = 0; j < cnt; j++)
{
if (!g[i][ver[j]]) //这个点与几何没有关联,这个点就不能加入团
{
res = false; //那么这个团就是一个最大团
break;
}
}
if (res)return false;
}
}
}
int main()
{
cin >> n >> m;
while (m--)
{
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 >> ver[i];
if (is_clique(cnt))
{
if (is_max_clique(cnt)) puts("Yes");
else puts("Not Maximal");
}
else puts("Not a Clique");
}
return 0;
}