不管如何,还是努力向上吧。
这题一开始想不出解法,本来想了想dfs,但没动手,就找了找题解原博客题解,然后发现一个数据结构中一个比较不显眼的知识点---并查集。
感觉自己都忘了,就仔细的找了找资料,研究这种解法。。。
并查集是一种集合表示,树的一个应用。基本的包括三种操作。
initial():初始化工作,一般为自己是自己的集合。
s find(x):找到x节点集合的名字,或者理解为找到其根节点。
union(x,y):将x和y并起来。即x,y内所有节点都联通了。
本题意思:去掉其中某一个城市,需要额外增加多少条路才能将剩下的城市全部联通起来。
代码如下(主要还是参照了上文中博客题解方法与思路~):
#include"stdio.h"
#include"string.h"
#include"math.h"
#include<iostream>
#include<vector>
#include<set>
#include<queue>
#include<string>
#include<algorithm>
using namespace std;
#define INF 0x7FFFFFFF
vector<vector<int>> map;
vector<int> check;
vector<int> mcity;
int n,m,k;
void initial(){
for(int i = 0;i < n;i++){
mcity[i] = i;
}
}
void compressTop(int xParent,int x){
if(mcity[x] != xParent){
compressTop(xParent,mcity[x]);
mcity[x] = xParent;
}
}
int findSet(int x){
if(mcity[x] != x){ //如果他的根不是他自己,就去找他父节点的根。
int xParent = findSet(mcity[x]);
compressTop(xParent,x);//找到之后,就想办法把x和找到的这个根联系起来,把所有的父节点们和这个根联系起来。
}
return mcity[x];
}
void unionSet(int x,int y){
int a = findSet(x);
int b = findSet(y);
mcity[a] = b;
}
int main(){
scanf("%d %d %d",&n,&m,&k);
map.resize(n);
mcity.resize(n);
check.resize(k);
for(int i = 0;i < m;i++){
int tempi,tempj;
scanf("%d %d",&tempi,&tempj);
tempi--;
tempj--;
map[tempi].push_back(tempj);
map[tempj].push_back(tempi);
}
for(int i = 0;i < k;i++){
scanf("%d",&check[i]);
}
for(int i = 0;i < k;i++){
int q = check[i];
q--;
initial();
for(int j = 0;j < n;j++){
for(int k = 0;k < map[j].size();k++){
int v = map[j][k]; //v和j是有路的
if(q!=j&&q!=v){ //找到和q没任何关系的两个点,然后union。
unionSet(j,v);
}
}
}
set<int> parentSet;
for(int i = 0;i < n;i++){
parentSet.insert(findSet(i)); //找到所有根节点。
}
//就像最后并集的只剩下几个根节点和待查找点q,比如找到5个根,但只需要连4个根,所以需要3根线。
printf("%d\n",parentSet.size() - 2);
}
int a;
cin>>a;
return 0;
}