割点的定义是,如果删除该顶
点后会使该无向图的连通分量(连通块)个数变多,那么就称该顶点为该无向图的割点。
求无向图的连通块个数的基本思路是,开一个 vis 数组表示顶点是否已访问,然后遍历所有
顶点,如果当前顶点还没有被访问,那么就访问该顶点所在的连通块,将该连通块中的所有顶
点都标记为已访问。而遍历连通块也只需要一个简单的 DFS 就能解决,书上 10.3 图的遍历这个
小节已经写得很清楚了。
至于删除顶点这个操作其实不必真的去删,只需要在 DFS 的时候判断一下是不是要被删掉
的这个顶点,是的话跳过这个顶点就行。
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXV = 1010; // 顶点数上限
bool G[MAXV][MAXV]; // 无向图G
bool vis[MAXV]; // 顶点是否已被访问
int n, m, deletedIdx; // 顶点数, 边数, 被删除的顶点编号
// 将顶点u所在的连通块里的顶点都标记为已访问
void DFS(int u) {
for(int v = 1; v <= n; v++) { // 遍历所有顶点
// 如果顶点v不是被删除的顶点,且边u<->v存在,且v还没有被访问
if(v != deletedIdx && G[u][v] && !vis[v]) {
vis[v] = true; // 标记顶点v为已访问
DFS(v); // 访问顶点v所在的连通块
}
}
}
// 计算连通块个数
int calSubGraphNumber() {
memset(vis, false, sizeof(vis)); // 初始化所有顶点为未访问
int num = 0; // 连通块个数
for(int i = 1; i <= n; i++) { // 遍历所有顶点
if(i != deletedIdx && !vis[i]) { // 如果顶点i不是被删除的顶点,且i所在的连通块还没有被访问
vis[i] = true; // 标记顶点i为已访问
DFS(i); // 访问顶点i所在的连通块,将连通块中的所有顶点都标记为已访问
num++; // 连通块个数加1
}
}
return num; // 返回连通块个数
}
int main() {
scanf("%d%d", &n, &m); // 顶点数, 边数
for(int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u][v] = G[v][u] = true; // 无向图的边
}
int originSubGraphNumber = calSubGraphNumber(); // 计算未删点之前的连通块数量
int k;
scanf("%d", &k); // 查询个数
while(k--) {
scanf("%d", &deletedIdx); // 被删除的顶点编号
int newSubGraphNumber = calSubGraphNumber(); // 计算删除顶点后的连通块数量
if(newSubGraphNumber > originSubGraphNumber) { // 如果连通块数量变多, 则输出YES, 否则输出NO
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}