来源:JZOJ,Luogu P1955
题目描述
在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设
x
1
,
x
2
,
x
3
,
⋯
x_1 ,x_2 ,x_3 ,⋯
x1,x2,x3,⋯ 代表程序中出现的变量,给定
n
n
n 个形如
x
i
x_i
xi =
x
j
x_j
xj 或
x
i
≠
x
j
x_i ≠x_j
xi=xj 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为:
x
1
=
x
2
,
x
2
=
x
3
,
x
3
=
x
4
,
x
4
≠
x
1
x_1 =x_2 ,x_2 =x_3 ,x_3 =x_4 ,x_4 ≠x_1
x1=x2,x2=x3,x3=x4,x4=x1,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。
输入格式
输入的第一行包含一个正整数 t t t ,表示需要判定的问题个数。注意这些问题之间是相互独立的。
对于每个问题,包含若干行:
第一行包含一个正整数 n n n ,表示该问题中需要被满足的约束条件个数。接下来 n n n 行,每行包括三个整数 i , j , e i,j,e i,j,e ,描述一个相等/不等的约束条件,相邻整数之间用单个空格隔开。若 e = 1 e=1 e=1,则该约束条件为 x i = x j x_i =x_j xi=xj 。若 e = 0 e=0 e=0 ,则该约束条件为 x i ≠ x j x_i ≠x_j xi=xj
输出格式
输出文件的第
k
k
k 行输出一个字符串 YES
或者 NO
(字母全部大写),YES
表示输入中的第
k
k
k 个问题判定为可以被满足,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
=
1
e=1
e=1 的情况,也就是
x
i
=
x
j
x_i=x_j
xi=xj,合并
x
i
x_i
xi 和
x
j
x_j
xj。然后,再依次判断
e
=
0
e=0
e=0 的情况,但是如果发现了
e
=
0
e=0
e=0 且
x
i
x_i
xi 和
x
j
x_j
xj 在同一颗树中,但因为
e
=
0
e=0
e=0,所以
x
i
x_i
xi 应该
≠
x
j
≠x_j
=xj,所以矛盾了,直接输出
NO
,return 0
就 o k ok ok 了
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;
}