星球大战

链接

这题并不简单,说实话,就算想到了关键解法(逆向思维)还会被时间卡住

相比于平常的并查集,这题需要逆向思维,由于我们并不方便在找到摧毁后的信息

所以我们反着来,假设要摧毁3号星球,我们可以排除与三号星球有关的合并(Union),这样就是摧毁后的答案了

为了方便且快速查找与某个星球有关的合并操作,我们可以写一个unordered_map,键负责存储每个星球,值存储vector(planet存储两个数据,分别是两个连接的星球)

在设置一个bool类型的数组destroyed,表示是否被摧毁,使用合并函数的时候只要合并的两个星球都满足destroyed[k]都为0就行

  #include<iostream>
#include<stack>
#include<unordered_map>
#include<vector>
#include<list>
using namespace std;
int n, m;
vector<int>num;
struct planet {
	int x, y;
};
unordered_map<int, vector<planet>>P;

int Find(int x) {
	if (num[x] < 0) {
		return x;
	}
	else {
		return num[x] = Find(num[x]);
	}
}

bool Union(int x, int y) {
	int root_x = Find(x);
	int root_y = Find(y);
	if (root_x != root_y) {
		if (num[root_x] < num[root_y]) {
			num[root_x] += num[root_y];
			num[root_y] = root_x;
		}
		else if (num[root_y] < num[root_x]) {
			num[root_y] += num[root_x];
			num[root_x] = root_y;
		}
		else {
			num[root_x] += num[root_y];
			num[root_y] = root_x;
		}
		return 1;
	}
	return 0;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n >> m;
	num.resize(n, -1);
	for (int i = 0;i < m;i++) {
		int x, y;
		cin >> x >> y;
		P[x].push_back({ x,y });
		P[y].push_back({ x,y });
	}
	int k;
	cin >> k;
	stack<int>st;
	vector<bool>destoryed(n, 0);
	for (int i = 0;i < k;i++) {
		int pl;
		cin >> pl;
		st.push(pl);
		destoryed[pl] = 1;
	}

	int count = n;
	count -= k;
	
	for (int i = 0;i < n;i++) {
		for (planet it : P[i]) {
			if (!destoryed[it.x] && !destoryed[it.y]) {
				if (Union(it.x, it.y)) {
					count--;
				}
			}
		}
	}
	stack<int>ans;
	ans.push(count);
	while (!st.empty()) {
		int cur = st.top();
		st.pop();
		count++;
		destoryed[cur] = 0;
		for (planet it : P[cur]) {
			if (!destoryed[it.x] && !destoryed[it.y]) {
				if (Union(it.x, it.y)) {
					count--;
				}
			}
		}
		ans.push(count);
	}
	while (!ans.empty()) {
		cout << ans.top() << '\n';
		ans.pop();
	}

}

当然,由于我存储了两次,

P[x].push_back({ x,y });

P[y].push_back({ x,y });

所有Union的调用会重复,不过没有影响(第二次二者就位于同一颗树上了,不会影响count,而且Find函数的调用是O(1)的,可以直接忽略了)

时间复杂度:O(m + k)

空间复杂度:O(n + m + k)

全部评论

相关推荐

昨天 00:12
已编辑
香港大学 Java
这里没熟人,吐槽一下吧,楼主语文不太好,语句可能不太通顺,想到哪说到哪。我只想说字节,你太狠了。。。作为一个校招生,字节landing实在是地狱级别,来到字节已经一个月了,在这一个月里,每天都承受着巨大的压力,每天起床感觉胸闷气短,饭也吃不下,一个月已经瘦了五六斤了(也算是变相减肥了),一想到上班就莫名其妙地喘不过气来,闭上眼脑子里都是代码。压力一方面来自于mt的压力,一方面是自己的压力。我参与的项目是几个月的新项目,项目很多不完善的地方,业务流程不完善,很多代码需要根据做产品的需求做大改动,而楼主从来没有做过业务方面的编码,所以在理解业务需求的时候,非常难受,而且业务线很长,作为承接上下游的中间系统,不仅要了解自己项目的流程,还要了解上下游的流程,导致上手非常困难,也有可能是楼主太菜了QAQ。。楼主12.17入职,一周之内就已经开始做需求了,第一个需求就是新增和修改数据,mt美名其曰给我练手,但是一个小小的新增和修改涉及了太多细节,在字段定义不明确、数据来源不了解、处理流程不清晰的情况下,楼主花了一周时间完成了这个需求,当然做技术方案评审的时候,被吊了好几次,修改了几版方案。需求做完,被测试找出来十几个缺陷,每天不是在修bug,就是在修bug的路上,修bug修的精疲力尽,每天自测都需要花费很长时间,导致lz每天都十分紧张,不敢打开飞书,生怕又收到QA的信息,并且产品设计及其粗糙,很多地方都需要再三确认,严重拖慢进度。好不容易做完还被嫌进度太慢,下一个需求就让我开天辟地,完成整个业务流程的编码,lz真的直冒汗啊啊啊,真把我当老员工对待啊。最重要的一点,mt从来不给正反馈,每次问问题都会被反问,这个流程你真的理解了么,这个需求你认真思考了么,站在用户角度思考了么,站在产品角度思考了么,站在前端角度思考了么,站在QA角度思考了么,总之得不到什么有用的回复,每次问问题都是煎熬,从来得不到肯定的回复,要不就是反问,要不就是让lz去问产品,去和其他人对齐,每次都不被肯定的滋味真的很难受,导致lz现在不敢问问题,生怕再被吊,真的难受啊啊。顺便说一嘴,字节的福利是真的好,饭菜也很好吃(虽然我不大能吃得下)。今天11点刚到家,洗漱完上床已经快12点了,今天先写到这里吧,给自己留半小时抖音时间,毕竟只有睡前的时间是属于自己的。世界是个巨大的围城,有人想进来,有人想出去,不正真体验过不知道自己想要的到底是什么。。加油吧。
喵_coding:唉 进不去的挤破头都想进去 进去了的又真觉得很累 这个世界究竟怎么了
工作压力大怎么缓解
点赞 评论 收藏
分享
牛客49732338...:同志们,已拿下
我的OC时间线
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务