來源:JZOJ,Luogu P1955
題目描述
在實現程序自動分析的過程中,常常需要判定一些約束條件是否能被同時滿足。
考慮一個約束滿足問題的簡化版本:假設 代表程序中出現的變量,給定 個形如 = 或 的變量相等/不等的約束條件,請判定是否可以分別爲每一個變量賦予恰當的值,使得上述所有約束條件同時被滿足。例如,一個問題中的約束條件爲:
,這些約束條件顯然是不可能同時被滿足的,因此這個問題應判定爲不可被滿足。
現在給出一些約束滿足問題,請分別對它們進行判定。
輸入格式
輸入的第一行包含一個正整數 ,表示需要判定的問題個數。注意這些問題之間是相互獨立的。
對於每個問題,包含若干行:
第一行包含一個正整數 ,表示該問題中需要被滿足的約束條件個數。接下來 行,每行包括三個整數 ,描述一個相等/不等的約束條件,相鄰整數之間用單個空格隔開。若 ,則該約束條件爲 。若 ,則該約束條件爲
輸出格式
輸出文件的第 行輸出一個字符串 YES
或者 NO
(字母全部大寫),YES
表示輸入中的第 個問題判定爲可以被滿足,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
- 然後,就是並查集了,先處理所有 的情況,也就是 ,合併 和 。然後,再依次判斷 的情況,但是如果發現了 且 和 在同一顆樹中,但因爲 ,所以 應該 ,所以矛盾了,直接輸出
NO
,return 0
就 了
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;
}