【题解】NOI2015 程序自动分析 【并查集】【离散化】
链接:https://ac.nowcoder.com/acm/contest/1031/A
题目描述
在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设 𝑥1, 𝑥2, 𝑥3, ⋯ 代表程序中出现的变量,给定 𝑛 个形如 𝑥𝑖 = 𝑥𝑗 或 𝑥𝑖 ≠ 𝑥𝑗 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为:
𝑥1 = 𝑥2, 𝑥2 = 𝑥3, 𝑥3 = 𝑥4, 𝑥1 ≠ 𝑥4 ,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。
输入描述:
第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”表示不可被满足。
备注:
1≤n≤100000
1≤i,j≤1000000000
题目分析:
考虑什么情况下是可以被满足的:
显然,如果所有的变量约束条件都是相等关系,那么一定是可以被满足的。只有存在不等关系时,才有可能与某些相等关系产生矛盾,从而不可以被满足。
对于相等关系,我们可以采用并查集来维护——集合S中的任两个元素均相等,对于一个元素a和集合S内的一个元素b,若a与b相等,那么a与集合S内任意元素均相等,那么a属于集合S。
对于不等关系,我们考虑什么情况会产生矛盾——如果a和b不属于同一集合S,那么不产生矛盾;如果a和b属于同一集合S,那么集合S内的任两个元素相等,则a与b相等,这和a与b不等矛盾!
综上,我们可以得出本题的解法:
先处理所有的相等关系,用并查集来维护。再处理不等关系,判断是否属于同一集合,若属于则不可以被满足。
需要注意的是,本题i和j的范围非常大,因此需要先进行离散化。
代码实现:
#include <bits/stdc++.h> using namespace std; const int maxn=2e5+10; int father[maxn]; map <int,int> id; int a[maxn],b[maxn],e[maxn]; int t; int n; int size; bool flag; int getfather(int u){ if(father[u]==u)return u; return father[u]=getfather(father[u]); } bool judge(int x,int y){ int xx,yy; xx=getfather(x); yy=getfather(y); if(xx==yy)return 1; return 0; } void merge(int x,int y){ int xx,yy; xx=getfather(x); yy=getfather(y); if(xx==yy)return; father[xx]=yy; } int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=2*n;i++){ father[i]=i; } id.clear(); size=0; flag=1; for(int i=1;i<=n;i++){ int x1,y1,e1; scanf("%d%d%d",&x1,&y1,&e1); if(id[x1]==0){ size++; id[x1]=size; } if(id[y1]==0){ size++; id[y1]=size; } a[i]=id[x1]; b[i]=id[y1]; e[i]=e1; } for(int i=1;i<=n;i++){ if(e[i]==1)merge(a[i],b[i]); } for(int i=1;i<=n;i++){ if(e[i]==0){ if(judge(a[i],b[i])){ flag=0; break; } } } if(flag)printf("YES\n"); else printf("NO\n"); } return 0; }
碎碎念:
并查集维护相等关系是常见的并查集应用。
一般来说,并查集适合维护一类具有“传递性”的问题:集合S中任两个元素具有关系X,若a和集合S内一元素b也具有关系X,那么a与集合S内任一元素都具有关系X。显然,相等关系是具有上述“传递性”的一个典型实例。
虽然阐述中借用了集合的概念,但是并查集与集合存在很大差异,二者绝不能混为一谈。比如,并查集是一个树形结构,存在一个特殊的根节点,而集合中各个元素的地位相同。
在边带权的并查集中,关系X会更加复杂,涉及到具体的数值,往往与根节点相关。
不会写离散化,写了个假的离散化上去.jpg
所以就算标题上打了个离散化,也没离散化,反正标题可以瞎起。
第一遍交的时候数组开小了,忘记×2了,不愧是我能干出来的事。

浙公网安备 33010602011771号