近几年这个题还挺高频的。
这种题目核心就是一个个把不在当前集合(用vector装着)的点,尝试能不能加入集合中。(如果和目前图中的点都互相之间有通路,就说明这个点是可以新加入的)。可以用viewed来标记集合中的节点。
所以整体流程如下:
1.用G矩阵来存储通路情况。
2.遍历当前输入的vector中的元素(如访问了 3,4,5,6),用viewed维护访问过的节点。
3.判断,如果vector内部都有不连通的,说明这个集合就在瞎搞,直接return出去。
3.如果一切正常,进行下一步判断,遍历所有节点(从1到N),用viewed里面的信息排除掉已经遍历过的(这样就搞出来了不在vector中的所有元素),一个个来尝试把这些点加进集合(遍历,如果和vector内某个点有通路,则通路数量cnt+1),到最后判断这个点的cnt是不是就是集合数量。
4.如果是集合数量,说明这个点可以加入到集合中,用一个tmp数组维护,到时候sort就好了。
5.如果不是,就啥也不用管,看下一个节点能不能加进去。
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
#include <queue>
using namespace std;
const int maxnum = 205;
const int INF = 99999;
int N, M;
int G[maxnum][maxnum];
bool viewed[maxnum];
vector<int> tmp; //可加入点
void Judge(vector<int> vec,int index)
{
fill(viewed, viewed + maxnum, false);
tmp.clear(); //清除上一轮的可加入点
int IsSummit = 1, IsMax = 1;
for (int i = 0; i < vec.size(); i++)
{
viewed[vec[i]] = true; //该节点标记为访问过
for (int j = i + 1; j < vec.size(); j++)
{
if (G[vec[i]][vec[j]] == INF)
{
IsSummit = 0;
printf("Area %d needs help.\n",index);
return;
}
}
}
for (int i = 1; i <= N; i++) //遍历所有点
{
if (viewed[i] == true) continue; //访问过的不用管
int cnt = 0;//与vec中点连通的数量
for (int j = 0; j < vec.size(); j++)
{
if (G[i][vec[j]] != INF) //能连通
++cnt;
}
if (cnt == vec.size()) //全都连通
{
IsMax = 0;
tmp.push_back(i); //推入可以加入的点
}
}
if(!tmp.empty())
sort(tmp.begin(), tmp.end()); //非空则排序
if (IsMax && IsSummit)
printf("Area %d is OK.\n",index);
else if (!IsMax && IsSummit)
{
printf("Area %d may invite more people, such as %d.\n",index,tmp[0]);
}
}
int main()
{
cin >> N >> M;
fill(G[0], G[0] + maxnum * maxnum, INF);
for (int i = 0; i < M; i++)
{
int a, b;
cin >> a >> b;
G[a][b] = G[b][a] = 1;
}
int K;
cin >> K;
for (int i = 0; i < K; i++)
{
int num;
cin >> num;
vector<int> vec(num);
for (int j = 0; j < num; j++)
cin >> vec[j];
Judge(vec,i+1);
}
return 0;
}