题目传送门luogu1955 题 目 传 送 门 l u o g u 1955
题目描述
在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设 x1,x2,x3... x 1 , x 2 , x 3 . . . 代表程序中出现的变量,给定 n n 个形如或 xi≠xj x i ≠ x j 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为: x1=x2,x2=x3,x3=x4,x4≠x1 x 1 = x 2 , x 2 = x 3 , x 3 = x 4 , x 4 ≠ x 1 ,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。
输入输出格式
输入格式:
输入文件的第1行包含1个正整数 t t ,表示需要判定的问题个数。注意这些问题之间是相互独立的。
对于每个问题,包含若干行:
第1行包含1个正整数,表示该问题中需要被满足的约束条件个数。接下来 n n 行,每行包括3个整数,描述1个相等/不等的约束条件,相邻整数之间用单个空格隔开。若 e=1 e = 1 ,则该约束条件为 xi=xj x i = x j ;若 e=0 e = 0 ,则该约束条件为 xi≠xj x i ≠ x j ;
输出格式:
输出文件包括 t t 行。
输出文件的第行输出一个字符串“YES” 或者“NO”(不包含引号,字母全部大写),“YES” 表示输入中的第 k k 个问题判定为可以被满足,“NO” 表示不可被满足。
输入输出样例
输入样例#1:
2
2
1 2 1
1 2 0
2
1 2 1
2 1 1
输出样例#1:
NO
YES
输入样例#2:
2
3
1 2 1
2 3 1
3 1 1
4
1 2 1
2 3 1
3 4 1
1 4 0
输出样例#2:
YES
NO
说明
【样例说明1】
在第一个问题中,约束条件为:。这两个约束条件互相矛盾,因此不可被同时满足。
在第二个问题中,约束条件为: x1=x2,x1=x2 x 1 = x 2 , x 1 = x 2 。这两个约束条件是等价的,可以被同时满足。
【样例说明2】
在第一个问题中,约束条件有三个: x1=x2,x2=x3,x3=x1 x 1 = x 2 , x 2 = x 3 , x 3 = x 1 。只需赋值使得x1=x1=x1,即可同时满足所有的约束条件。
在第二个问题中,约束条件有四个: x1=x2,x2=x3,x3=x4,x4≠x1 x 1 = x 2 , x 2 = x 3 , x 3 = x 4 , x 4 ≠ x 1 。由前三个约束条件可以推出 x1=x2=x3=x4 x 1 = x 2 = x 3 = x 4 ,然而最后一个约束条件却要求 x1≠x4 x 1 ≠ x 4 ,因此不可被满足。
【数据范围】
【时限2s,内存512M】
题解
这道题目可以写个程序自动分析
因为这道题目只有相等和不等这两种约束条件,所以我们可以分开判断。
因为”相等“约束之间没有约束,所以我们可以先做”相等“,再做”不等“。
我们将变量看成点,”相等“约束看成边,我们就可以构造一张无向图,其中,两个连通的点所对应的变量相等。
接着我们做”不等“的约束。若”不等“所约束的两个变量连通,则不可被满足。
所以,我们需要一个能够合并两个集合以及查询所在集合的数据结构,容易想到用并查集。
虽然
i,j≤109
i
,
j
≤
10
9
,但是最多只有
2n
2
n
个有用的变量,所以可以先离散化一下。
空间
O(N)
O
(
N
)
,时间
O(Nα(N))
O
(
N
α
(
N
)
)
。
其中
O(α(N))
O
(
α
(
N
)
)
为反阿克曼函数,当
N≤221019729
N
≤
2
2
10
19729
时,
α(N)<5
α
(
N
)
<
5
,所以说,看作常数就好了。
总结
并查集的两个操作:合并两个集合以及查询所在集合,使得它能够维护一张无向图中节点的连通性。扩展一下,它还能够动态维护许多具有传递性的关系,如题中的”相等“约束。综上,需要维护无向图中节点连通性时,可以考虑并查集。
标程
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 50;
struct Ques{
int u, v, w;
Ques(int _u = 0, int _v = 0, int _w = 0)
{
u = _u; v = _v; w = _w;
}
bool operator <(const Ques &t) const
{
return w > t.w;
}
}q[N];
int t, a[N], f[N];
int find(int x)
{
return f[x] == x ? x : f[x] = find(f[x]);
}
int main()
{
ios::sync_with_stdio(false);
cin >> t;
for (int m, n; t--; )
{
cin >> m; n = 0;
for (int i = 1; i <= m; i++)
{
cin >> q[i].u >> q[i].v >> q[i].w;
a[++n] = q[i].u; a[++n] = q[i].v;
}
sort(q + 1, q + m + 1);
sort(a + 1, a + n + 1);
n = unique(a + 1, a + n + 1) - a - 1;
for (int i = 1; i <= n; i++) f[i] = i;
bool p = 1;
for (int i = 1; i <= m && p; i++)
{
q[i].u = lower_bound(a + 1, a + n + 1, q[i].u) - a;
q[i].v = lower_bound(a + 1, a + n + 1, q[i].v) - a;
if (q[i].w) f[find(q[i].u)] = find(q[i].v);
else if (find(q[i].u) == find(q[i].v)) p = 0;
}
puts(p ? "YES" : "NO");
}
return 0;
}