ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

acwing237

2022-05-30 20:32:23  阅读:168  来源: 互联网

标签:结点 int father acwing237 编号 find neq


这道题一眼就知道是并查集,创个int型数组按步骤写就好了。
哈哈如果这样想简单了就错了。看一下题目的数据范围:

编号最大值达到了\(10^9\),但是不同的编号最多只有\(2\times 10^5\)个,问题就出在这里。如果创建一个有10亿个元素的int数组,那内存明显不够用。所以需要将数组离散化。这里使用STL的unordered_map来储存,key为结点的编号,value为父结点的编号。(为什么不能用map?因为map的find操作是对数时间的,而为了达到数组随机存储的常数时间,需要使用unordered_map,它使用了哈希表,可以在常数时间内存取)
所以,算法的流程如下:

维护两个容器father和neq,前者储存并查集,后者储存不相等关系的结点编号。
创建一个函数add,若结点已经在并查集中,不做任何处理;否则将其加入并查集并初始化。
每读入一个表达式,就进行判断:若表达式的符号为=,就使用add函数处理表达式的两个结点编号,然后进行union操作;否则的话,使用add函数处理表达式的两个结点编号,然后将这两个结点的编号加入neq容器。
遍历完所有表达式后,遍历neq容器中的所有编号对,对其进行find操作。若存在一堆编号在同一个set中,说明条件不可满足,退出循环。


注意,由于数据量较大,所以应该对并查集进行路径压缩,推荐使用递归的方法来书写。同时,数据量大所以要加入该语句从而加速I/O

ios::sync_with_stdio(false);

代码如下:

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<unordered_map>		
#include<vector>

using namespace std;

int t;
//使用哈希表离散化储存数据,key为结点编号,value为父结点的编号,注意,每轮循环结束要clear
unordered_map<int, int> father;
//储存当前判定的所有不等于条件,注意,每轮循环结束要clear
vector<pair<int, int>> neq;


//使用路径压缩
int findfather(int i) {
	if (father[i] == i)	return i;
	int root = findfather(father[i]);
	father[i] = root;
	return root;
}

//判断两个节点是否在同一个set中
bool find(int i,int j) {
	return findfather(i) == findfather(j);
}

//union两个set
void myunion(int i,int j) {
	if (!find(i, j)) {
		int r1, r2;
		r1 = findfather(i);
		r2 = findfather(j);
		father[r2] = r1;
	}
}

//将i,j加入father,若已存在则不处理,否则将其加入并初始化
void add(int i, int j) {
	if (father.find(i) == father.end()) {
		father.insert(pair<int, int>(i, i));
	}
	if (father.find(j) == father.end()) {
		father.insert(pair<int, int>(j, j));
	}
}

int main(void) {
	//关闭同步,加速io
	ios::sync_with_stdio(false);

	cin >> t;
	while (t-- > 0) {
		//条件数
		int qnum;
		cin >> qnum;
		int i, j, e;
		while (qnum-- > 0) {
			cin >> i >> j >> e;
			if (e == 1) {
				//先离散化储存,然后union
				add(i, j);
				myunion(i, j);
			}
			else if (e == 0) {
				//先离散化储存,然后存储不相等的数据
				add(i, j);
				neq.push_back(pair<int, int>(i, j));
			}
		}

		//遍历所有不等于的条件,判断节点是否在一个set中
		bool flag=true;
		for (int k = 0; k < neq.size(); k++) {
			int i, j;
			i = neq[k].first;
			j = neq[k].second;
			if (find(i, j)) {
				flag = false;
				break;
			}
		}

		if (flag)
			cout << "YES" << endl;
		else
			cout << "NO" << endl;

		//清空father,neq容器
		father.clear();
		neq.clear();
	}
}

标签:结点,int,father,acwing237,编号,find,neq
来源: https://www.cnblogs.com/biginsulator/p/16328122.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有