Luogu P1955 [NOI2015]程序自動分析 (離散化,並查集)

來源:JZOJ,Luogu P1955

題目描述

在實現程序自動分析的過程中,常常需要判定一些約束條件是否能被同時滿足。

考慮一個約束滿足問題的簡化版本:假設 x1,x2,x3,x_1 ,x_2 ,x_3 ,⋯ 代表程序中出現的變量,給定 nn 個形如 xix_i = xjx_jxixjx_i ≠x_j 的變量相等/不等的約束條件,請判定是否可以分別爲每一個變量賦予恰當的值,使得上述所有約束條件同時被滿足。例如,一個問題中的約束條件爲:
x1=x2,x2=x3,x3=x4,x4x1x_1 =x_2 ,x_2 =x_3 ,x_3 =x_4 ,x_4 ≠x_1,這些約束條件顯然是不可能同時被滿足的,因此這個問題應判定爲不可被滿足。

現在給出一些約束滿足問題,請分別對它們進行判定。

輸入格式

輸入的第一行包含一個正整數 tt ,表示需要判定的問題個數。注意這些問題之間是相互獨立的。

對於每個問題,包含若干行:

第一行包含一個正整數 nn ,表示該問題中需要被滿足的約束條件個數。接下來 nn 行,每行包括三個整數 i,j,ei,j,e ,描述一個相等/不等的約束條件,相鄰整數之間用單個空格隔開。若 e=1e=1,則該約束條件爲 xi=xjx_i =x_j 。若 e=0e=0 ,則該約束條件爲 xixjx_i ≠x_j

輸出格式

輸出文件的第 kk 行輸出一個字符串 YES 或者 NO(字母全部大寫),YES 表示輸入中的第 kk 個問題判定爲可以被滿足,NO 表示不可被滿足。

樣例數據

input

2
2
1 2 1
1 2 0
2
1 2 1
2 1 1

output

NO
YES

input

2
3
1 2 1
2 3 1
3 1 1
4
1 2 1
2 3 1
3 4 1
1 4 0

output

YES
NO

解題思路

  • 首先因爲這道題數據較大,所以想做這道題得先學會基礎 離散化,不會離散化的請移步這裏 QAQ
  • 然後,就是並查集了,先處理所有 e=1e=1 的情況,也就是 xi=xjx_i=x_j,合併 xix_ixjx_j。然後,再依次判斷 e=0e=0 的情況,但是如果發現了 e=0e=0xix_ixjx_j 在同一顆樹中,但因爲 e=0e=0,所以 xix_i 應該 xj≠x_j,所以矛盾了,直接輸出 NOreturn 0okok

Code

#include <bits/stdc++.h>
using namespace std;
int fa[1000005],b[1000005];
struct node
{
	int x,y,e;
}a[1000005];
int getfather(int k)  //尋找祖先節點
{
	if (fa[k]==k) return k;
	return fa[k]=getfather(fa[k]);
}
void merge(int x,int y)  //合併
{
	int fx=getfather(x);
	int fy=getfather(y);
	fa[fx]=fa[fy];
}
bool judge(int x,int y)  //判斷是否在同一棵樹內
{
	int fx=getfather(x);
	int fy=getfather(y);
	return (fx==fy);
}
void init()
{
	freopen("prog.in","r",stdin);
	freopen("prog.out","w",stdout);
}
void work()
{
	memset(a,0,sizeof(a));
	memset(fa,0,sizeof(fa));
	memset(b,0,sizeof(b));
	int n;
	scanf("%d",&n);
	int len=0;
	for (int i=1;i<=n;i++)
	{
		scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].e);
		b[++len]=a[i].x,b[++len]=a[i].y;
	}
	sort(b+1,b+len+1);
	len=unique(b+1,b+len+1)-(b+1);
	for (int i=1;i<=n;i++)
	{
		a[i].x=lower_bound(b+1,b+len+1,a[i].x)-b;  //離散化
		a[i].y=lower_bound(b+1,b+len+1,a[i].y)-b;
	}
	
	for (int i=1;i<=len;i++) fa[i]=i;  //初始每個節點的父親都是本身
	for (int i=1;i<=n;i++)
	{
		if (a[i].e) merge(a[i].x,a[i].y);  //合併
	}
	for (int i=1;i<=n;i++)
	{
		if (!a[i].e && judge(a[i].x,a[i].y))  //矛盾
		{
			printf("NO\n");
			return;
		}
	}
	printf("YES\n");
}
int main()
{
	init();
	int T;
	scanf("%d",&T);
	while (T--) work();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章