
本文共 3103 字,大约阅读时间需要 10 分钟。
题目描述
在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设 x 1 x_1 x1, x 2 x_2 x2, x 3 x_3 x3,…代表程序中出现的变量,给定 n n n个形如 x i = x j x_i=x_j xi=xj或 x i ≠ x j x_i≠x_j xi=xj的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为: x 1 = x 2 x_1=x_2 x1=x2, x 2 = x 3 x_2=x_3 x2=x3, x 3 = x 4 x_3=x_4 x3=x4, x 1 ≠ x 4 x_1≠x_4 x1=x4,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。
输入格式
输入文件的第 1 1 1行包含 1 1 1个正整数 t t t,表示需要判定的问题个数。注意这些问题之间是相互独立的。
对于每个问题,包含若干行:
第 1 1 1行包含 1 1 1个正整数 n n n,表示该问题中需要被满足的约束条件个数。
接下来 n n n行,每行包括 3 3 3个整数 i i i, j j j, e e e,描述 1 1 1个相等/不等的约束条件,相邻整数之间用单个空格隔开。若 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。
输出格式
输出文件包括 t t t行。 输出文件的第 k k k行输出一个字符串“YES”或者“NO”(不包含引号,字母全部大写),“YES”表示输入中的第 k k k个问题判定为可以被满足,“NO”表示不可被满足。
样例
输入
221 2 11 2 021 2 12 1 1
输出
NOYES
数据范围与提示
对于所有的数据, 1 ≤ t ≤ 10 1 \leq t \leq 10 1≤t≤10, 1 ≤ n ≤ 1 0 6 1 \leq n \leq 10^6 1≤n≤106, 1 ≤ i , j ≤ 1 0 9 1 \leq i,j \leq 10^9 1≤i,j≤109。
分析
显然,这是一道并查集的题。
因为 i , j i,j i,j两数有可能很大, f a fa fa数组很可能装不下,而 1 ≤ n ≤ 1 0 6 1 \leq n \leq 10^6 1≤n≤106, f a fa fa数组是可以装下的,所以考虑离散化。
做法:循环一遍,将 i = j i=j i=j的情况存在 f a fa fa数组中。再循环一遍,考虑 i ≠ j i \neq j i=j的情况,若 f a fa fa数组中 i i i和 j j j的父亲相等了,就说明矛盾了。
时间复杂度: O ( T n l o g 2 ( n ) ) O(Tnlog_2(n)) O(Tnlog2(n))。
代码
#include <cstdio>#include <algorithm>#include <cmath>#include <climits>#include <cstring>using namespace std;const int MAXN = 1e6 + 5;int fa[MAXN], Rank[MAXN], cnt, X[MAXN], Y[MAXN], Z[MAXN], lsh[MAXN << 1], Size, num[MAXN][2];bool flag;void read(int &x) { //读优 int f = 1; x = 0; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + (c - '0'); c = getchar(); } x *= f;}void Make_Set(int n) { //初始化 for(int i = 1; i <= n; i ++) { fa[i] = i; Rank[i] = 0; } return;}int Find_Set(int x) { //找父亲(路径压缩) if(fa[x] != x) { return fa[x] = Find_Set(fa[x]); } return fa[x];}void Union_Set(int x, int y) { //按秩合并 int i = Find_Set(x), j = Find_Set(y); if(i == j) return; if(Rank[i] < Rank[j]) fa[i] = j; else { fa[j] = i; if(Rank[i] == Rank[j]) Rank[i] ++; } return;}bool Union_Sets(int x, int y) { //判断是否矛盾 int i = Find_Set(x), j = Find_Set(y); if(i == j) return 1; return 0;}int main() { int T, n; read(T); while(T --) { memset(lsh, 0, sizeof(lsh)); cnt = 0; flag = 1; read(n); for(int i = 1; i <= n; i ++) { read(X[i]); read(Y[i]); read(Z[i]); lsh[++ cnt] = X[i]; lsh[++ cnt] = Y[i]; } sort(lsh + 1, lsh + 1 + cnt); Size = unique(lsh + 1, lsh + 1 + cnt) - lsh - 1; Make_Set(Size); for(int i = 1; i <= n; i ++) { num[i][0] = lower_bound(lsh + 1, lsh + 1 + Size, X[i]) - lsh;//离散化 num[i][1] = lower_bound(lsh + 1, lsh + 1 + Size, Y[i]) - lsh; } for(int i = 1; i <= n; i ++) { if(Z[i] == 1) Union_Set(num[i][0], num[i][1]); } for(int i = 1; i <= n; i ++) { if(Z[i] == 0 && Union_Sets(num[i][0], num[i][1])) { flag = 0; printf("NO\n"); break; } } if(flag) { printf("YES\n"); } } return 0;}
发表评论
最新留言
关于作者
