【问题描述】
在实现 程序自动分析 的过程 中,常 需要判定一些 约束 条件是否能被 同时 满 足。
考虑 一个约束满足问题 的简化版本: 假设 x1,x2,x3,⋯ 代表 程序中出现的变 量,给定 n 个形如 xi=xj或 xi≠xj 的变量相等 变量相等 变量相等 变量相等 /不等 的约束 条件 ,请判定 是否 可以 分别 为每一个变量 赋予恰当的 值, 使得上述所有 约束 条件同时被 满足 。例如 , 一个问题 一个问题 中的约束 条件 为:x1=x2,x2=x3,x3=x4,x1≠x4 ,这些约束条件 ,这些约束条件 ,这些约束条件 显 然是不可 能同时被 满足的 ,因此 这个问题 应判定为不可被满足 。
现在给出一些约束满足 问题,请分别 对它们进行 判定。
【输入格式】
输入文件的第 1 行包含 1 个正整数 t ,表示 ,表示 需要判定的问题个数 。注意这些 注意这些 注意这些 问题 之间 是相互独立的。 是相互独立的。 是相互独立的。
对于每个 问题 ,包含 若干行 :
第 1 行包含 1 个正整数n ,表示 该问题中需要被满足的 约束 条件 个数 。
接下来 n行,每包括 行,每包括 3 个整数 i,j,e ,描述 1 个相等 /不等的 约束 条件 ,相 邻整数之间用单个 整数之间用单个 整数之间用单个 整数之间用单个 空格隔开。 空格隔开。 空格隔开。 若 e=1 ,则 该约束条件为 该约束条件为 该约束条件为 该约束条件为 xi= xj ;若 e=0 , 则该约束条件为 xi ≠ xj
【输出格式】
输出 文件包括 t 行。
输出 文件的 第 k行输出 一个字符串“ 一个字符串“ YES ”或者 “NO ”(不包含引号,字母 (不包含引号,字母 (不包含引号,字母 (不包含引号,字母 (不包含引号,字母 (不包含引号,字母 (不包含引号,字母 全部大写) 全部大写) 全部大写) ,“YES ”表示 输入中的第 k 个问题 判定为 可以 被满足, “NO ”表示不 可被满足。
哦很久没写blog了。。本沙茶这次NOI网赛唯一全A的一题 T_T 。。
这题一眼并查集,因为等号具有传递性,将所有用等号连接的集合合并一下就行了。但是要注意只能开一个并查集来维护所有等量关系,千万不要在开一个维护不等关系!(a!=b, b!=c, 合并后会推出a!=c,然而并不一定这样)先将所有等量关系维护后,再弄依次判断不等关系是否和集合冲突即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1000010;
int N, T;
int fa[MAXN*2];
void get(int &r) { //n很大,数据组数也多,最好加读入外挂
char c; r=0;
do c=getchar(); while (c<'0'||c>'9');
do{r=r*10+c-'0';c=getchar();}while (c>='0'&&c<='9');
}
int data[MAXN][2]; //记录输入数据以离散化
int b[MAXN*2]; //记录是等号还是不等号
int arr[MAXN * 2], cnt, len;
int bifind(int x) { //二分查找(lower_bound比手写的慢三倍。。)
int l = 1, r = len, mid = (l + r) >> 1;
while (l < r) {
if (arr[mid] == x) return mid;
if (arr[mid] < x) l = mid + 1;
else r = mid - 1;
mid = (l + r) >> 1;
}
return mid;
}
struct Stack { //无聊的手写栈
int sta[MAXN*2], tp;
bool empty() {return tp==0;}
int top() {return sta[tp];}
void push(int x) {sta[++tp]=x;}
void pop() {--tp;}
void clear() {tp=0;}
} z;
void init() {
for (int i = 1; i<=len; ++i) //这里是len不是n。。n是关系的个数,len才是变量个数
fa[i] = i;
}
int root(int x) { //用手写栈实现的路径压缩防止递归爆栈。然而由于路径压缩的存在并不需要。。
while (fa[x] != x && x != -1) z.push(x), x = fa[x];
while (!z.empty()) fa[z.top()] = x, z.pop();
return x;
}
bool solve() {
init();
int i, t1, t2;
for (i = 1; i<=N; ++i) //先将所有相等关系合并成集合
if (b[i] == 1) {
t1 = bifind(data[i][0]);
t2 = bifind(data[i][1]);
if (root(t1) != root(t2))
fa[root(t1)] = root(t2);
}
for (i = 1; i<=N; ++i)
if (b[i] == 0) {
t1 = bifind(data[i][0]);
t2 = bifind(data[i][1]);
if (root(t1) == root(t2)) //检查是否冲突
return 0;
}
return 1;
}
int main()
{
//freopen("prog.in", "r", stdin);
//freopen("prog.out", "w", stdout);
int i;
get(T);
while (T--) {
get(N);
cnt = 0;
for (i = 1; i<=N; ++i) {
get(data[i][0]); get(data[i][1]);
get(b[i]);
arr[++cnt] = data[i][0];
arr[++cnt] = data[i][1];
}
sort(arr+1, arr+cnt+1);
len = unique(arr+1, arr+cnt+1) - (arr+1); //len保存离散化后变量个数(重复出现不计)
if (solve()) puts("YES");
else puts("NO");
}
return 0;
}