【专题】并查集判断冲突

(1)题目

P1955 [NOI2015] 程序自动分析 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

(2)解决思路

先排序,把所有e==1的操作放在前面,然后再进行e==0的操作在进行e==1的操作的时候,我们只要把它约束的两个变量放在同一个集合里面即可。在e==0,即存在一条不相等的约束条件,对于它约束的两个变量,如果在一个集合里面,那就不可能满足!如不相等的约束条件都满足,那就YES。

(3)50分代码

#include
#define maxn 100001
using namespace std;
int fa[maxn];
struct node{
	int x,y,z;
}a[maxn];
bool cmp(node a,node b){
	return a.z>b.z;
}
int Find(int x){
	return x==fa[x] ? x : fa[x]=Find(fa[x]);
}
int main(){
	int n,T;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		//初始化
		for(int i=1;i<=n;i++) fa[i]=i;
		memset(a,0,sizeof(a));
		//读入数据 
		for(int i=1;i<=n;i++){
			scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
		}
		sort(a+1,a+1+n,cmp);
		bool flag=0;
		for(int i=1;i<=n;i++){
			int fx=Find(a[i].x);
			int fy=Find(a[i].y);
			if(a[i].z==1){
				fa[fx]=fy;
			}else{
				if(fx==fy){
					printf("NO\n");
					flag=1;
					break;
				}
			}
		}
		if(!flag) printf("YES\n");		
	}
	return 0;
}

(4)问题

但是我们最后发现


【专题】并查集判断冲突_第1张图片                                               


t很大,fa数组根本存不下,但n可以存下呀,fa开了许多用不到的空间。

这是我们可以想到用离散化,fa我们不开数字大小,而是开够有多少数字即可

最后把数字离散化为它排第几就可以了

(5)离散化

		//读入数据 
		for(int i=1;i<=n;i++){
			scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
			book[++tot]=a[i].x;
			book[++tot]=a[i].y;
		}
		//离散化
		sort(book+1,book+1+tot);
		int reu=unique(book+1,book+tot+1)-book-1;
		//把a数组的数字大小改为数字排名 
		for(int i=1;i<=n;i++){
			a[i].x=lower_bound(book+1,book+1+reu,a[i].x)-book;
			a[i].y=lower_bound(book+1,book+1+reu,a[i].y)-book;
		}

(6)AC

#include
#define maxn 1000001
using namespace std;
int fa[maxn<<1];
int book[maxn<<1];
struct node{
	int x,y,z;
}a[maxn];
bool cmp(node a,node b){
	return a.z>b.z;
}
int Find(int x){
	return x==fa[x] ? x : fa[x]=Find(fa[x]);
}
int main(){
	int n,T,tot;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		//初始化
		for(int i=1;i<=(n<<1);i++) fa[i]=i;
		memset(a,0,sizeof(a));
		memset(book,0,sizeof(book));
		tot=0;
		//读入数据 
		for(int i=1;i<=n;i++){
			scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
			book[++tot]=a[i].x;
			book[++tot]=a[i].y;
		}
		//离散化
		sort(book+1,book+1+tot);
		int reu=unique(book+1,book+tot+1)-book-1;
		//把a数组的数字大小改为数字排名 
		for(int i=1;i<=n;i++){
			a[i].x=lower_bound(book+1,book+1+reu,a[i].x)-book;
			a[i].y=lower_bound(book+1,book+1+reu,a[i].y)-book;
		}
		//并查集 
		sort(a+1,a+1+n,cmp);
		bool flag=0;
		for(int i=1;i<=n;i++){
			int fx=Find(a[i].x);
			int fy=Find(a[i].y);
			if(a[i].z==1){
				fa[fx]=fy;
			}else{
				if(fx==fy){
					printf("NO\n");
					flag=1;
					break;
				}
			}
		}
		if(!flag) printf("YES\n");		
	}
	return 0;
}

(7)提示

【1】

在离散化后fa和book数组要开n的二倍哦!

因为有x和y两个数据!数量规模都扩大了二倍

【2】

因为数组下标从1开始,函数调用要注意,该加1要加1,该减1要减1!

【专题】并查集判断冲突_第2张图片


你可能感兴趣的:(专题,算法)