1013. Battle Over Cities (25)

不管如何,还是努力向上吧。

这题一开始想不出解法,本来想了想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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值