题目
因为需要考PAT甲级,所以最近一直在重新刷以前不知道怎么就刷过(主要是当时实在是什么都不懂,学习了什么知识,都是一知半解的)的题目,觉得收获很大。
看了《算法笔记》,这道题目,转化过来,其实就是求无向图中连通块的个数问题。这里两种做法,一种是dfs执行的次数,一种是并查集中集合个数。
也明白了连通块的含义(离散数学没学好,就是一直刷题,理论上不知道叫这个名字)
dfs版:
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
vector<int> G[N];
bool vis[N];
int n, m, k, point;
void dfs(int v){
vis[v]=true;
for(int i=0; i<(int)G[v].size(); i++){
if(!vis[G[v][i]] && v!=point){
dfs(G[v][i]);
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
int a, b;
for(int i=0; i<m; i++){
scanf("%d%d", &a, &b);
G[a].push_back(b);
G[b].push_back(a);
}
for(int i=0; i<k; i++){
scanf("%d", &point);
int block=0;
memset(vis, false, sizeof vis);
for(int j=1; j<=n; j++){
if(!vis[j] && j!=point){
dfs(j);
block+=1;
}
}
printf("%d\n", block-1);
}
return 0;
}
并查集版:
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
vector<int> G[N];
int n, m, k, father[N];
bool vis[N];
void init(){
memset(vis, false, sizeof vis);
for(int i=1; i<=n; i++){
father[i]=i;
}
}
int findFather(int x){
int a=x;
while(x!=father[x]){
x=father[x];
}
while(a!=father[a]){
int z=a;
father[z]=x;
a=father[a];
}
return x;
}
void Union(int a, int b){
int fa=findFather(a);
int fb=findFather(b);
if(fa!=fb){
father[fa]=fb;
}
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
int a, b;
for(int i=0; i<m; i++){
scanf("%d%d", &a, &b);
G[a].push_back(b);
G[b].push_back(a);
}
for(int i=0; i<k; i++){
scanf("%d", &a);
init();
for(int j=1; j<=n; j++){
for(int l=0; l<(int)G[j].size(); l++){
b=G[j][l];
if(j==a || b==a)
continue;
Union(j, b);
}
}
int block=0;
for(int j=1; j<=n; j++){
if(j==a)
continue;
int f=findFather(j);
if(!vis[f]){
block+=1;
vis[f]=true;
}
}
printf("%d\n", block-1);
}
return 0;
}