题意
第一行给出n、m、k,表示有n个城市,给出m条路,k个被敌人占领的点。
接下去给出m行,每行有两个数x、y,表示x和y之间存在一条路(双向路)。
最后给出k个被敌人占领的点(设每个点为id),如果点id被占领,那么和点id相连接的所有路都无法走。
问如果我们想要剩下的所有城市可以相互访问到,需要再修几条路。
思路
第一种思路:在k个城市遍历的时候,我们求出除了id点之外,剩下的城市中有多少连通块,每次询问把剩下所有城市连接起来需要修建道路的答案数量就是:连通块 - 1。代码见下方。
第二种思路:并查集,见:https://zhanglong.blog.csdn.net/article/details/113777370。
第三种思路:拓扑排序,自行查找。
注意
-
牛客上交的话要特判一下n==1的情况,PTA不用。
-
因为DFS所以要标记,但是因为本题间接求联通块所以不用回溯标记,这个要记住。
联通块AC代码
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<map>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const int N=1010;
int n,m,k,e[N][N],id;
bool book[N];
void dfs(int x)
{
for(int i=1;i<=n;i++)
{
if(i!=id&&e[x][i]&&!book[i]) // if(i!=x&&e[x][i]&&!book[i])
book[i]=1,dfs(i); // book[i]=0; 求连通块的话,不用递归回溯
}
}
int main()
{
cin>>n>>m>>k;
if(n==1)
{
cout<<0<<endl;
return 0;
}
for(int i=0;i<m;i++)
{
int x,y;
cin>>x>>y;
e[x][y]=e[y][x]=1;
}
for(int i=0;i<k;i++)
{
int ans=0;
cin>>id; // 排出x点和与x相连的所有边,求剩下所有点的连通块
memset(book,0,sizeof(book));
for(int j=1;j<=n;j++)
{
if(id!=j&&!book[j])
book[j]=1,dfs(j),ans++;
}
cout<<ans-1<<endl;
}
return 0;
}