C/C++教程

acwing237

本文主要是介绍acwing237,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

这道题一眼就知道是并查集,创个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();
	}
}
这篇关于acwing237的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!