程序自动分析(并查集、离散化)
程序自动分析(并查集、离散化)
链接:https://ac.nowcoder.com/acm/problem/17881
来源:牛客网
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设 𝑥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”表示不可被满足。
输入
2 2 1 2 1 1 2 0 2 1 2 1 2 1 1
输出
NO
YES
说明
在第一个问题中,约束条件为:x1=x2,x1≠x2。这两个约束条件互相矛盾,因此不可被同时满足。
在第二个问题中,约束条件为:x1=x2,x2=x1。这两个约束条件是等价的,可以被同时满足。
备注:
1≤n≤100000
1≤i,j≤1000000000
数据规模很大,下标到了1e9,开不下那么大的数组,所以要离散化
最简单的可以用unordered_map去代替原来的fa数组
1 #include <bits/stdc++.h> 2 typedef long long LL; 3 #define pb push_back 4 #define mst(a) memset(a,0,sizeof(a)) 5 const int INF = 0x3f3f3f3f; 6 const double eps = 1e-8; 7 const int mod = 1e9+7; 8 const int maxn = 1e5+10; 9 using namespace std; 10 11 vector<pair<int,int> > vt; 12 unordered_map<int,int> fa; 13 int Find(int x) 14 { 15 return fa[x]==x? x:fa[x]=Find(fa[x]); 16 } 17 void Union(int x,int y) 18 { 19 int xx = Find(x), yy = Find(y); 20 if(xx!=yy) fa[xx] = yy; 21 } 22 23 int main() 24 { 25 #ifdef DEBUG 26 freopen("sample.txt","r",stdin); //freopen("data.out", "w", stdout); 27 #endif 28 29 int T; 30 scanf("%d",&T); 31 while(T--) 32 { 33 fa.clear(); vt.clear(); 34 int n; 35 scanf("%d",&n); 36 for(int i=1;i<=n;i++) 37 { 38 int x,y,op; 39 scanf("%d %d %d",&x,&y,&op); 40 if(!fa[x]) fa[x] = x; 41 if(!fa[y]) fa[y] = y; 42 if(op==1) Union(x,y); 43 else vt.push_back({x,y}); 44 } 45 int ok = 1; 46 for(auto it:vt) 47 { 48 if(Find(it.first)==Find(it.second)) 49 { 50 ok = 0; 51 break; 52 } 53 } 54 printf(ok? "YES\n":"NO\n"); 55 } 56 57 return 0; 58 }
诈胡AC方法
from:https://blog.nowcoder.net/n/15516d835fc1475382f5d0e573ec9e53
对于1000000000数量级的i和j 我们将它,mod上一个较大,但是又没那么大的数。
比如mod上1e6+7 这样所有的i和j就强行缩小到我们可以接受的1e6 数量级了,再对这个范围进行并查集,应该就都没有问题了吧。
他的数据量 N 是小于100000的, 那你把所有的数mod完以后 很难出现重数的情况,就算出现wa的情况,你改改这个mod,依然有大概率可以AC的。
#include<iostream> #include<algorithm> #include<queue> #include<string> #include<cstdio> #include<cstring> #include<queue> #include<vector> #include<stack> #include<set> #include<map> #define ll long long using namespace std; #define close_stdin ios::sync_with_stdio(false) const int mod = 1e6 + 7; int fa[1000007]; struct node { int x, y; }; vector<node> vec; //并查集常用操作 merge 与find int find(int x) { return(fa[x]==x?x:fa[x]=find(fa[x])); } void merge(int x, int y) { fa[find(x)] = find(y); } void solve() { for (int i = 1;i <= mod;i++) { fa[i] = i; } int n; vector<node>vec; cin >> n; while (n--) { int i, j, e; cin >> i >> j >> e; i %= mod;j %= mod; if(!e){ node temp; temp.x = i;temp.y = j; vec.push_back(temp); } else { merge(i, j); } } for (auto w : vec) { if (find(w.x) == find(w.y)) { cout << "NO\n";return; } } cout << "YES\n"; } int main() { close_stdin;//只是为了让cin和printf一样快 int T; cin >> T; while (T--) { solve(); } }
-

浙公网安备 33010602011771号