【NOI2015】程序自動分析
題目描述
在實現程序自動分析的過程中,常常需要判定一些約束條件是否能被同時滿足。
考慮一個約束滿足問題的簡化版本:假設x1,x2,x3...代表程序中出現的變量,給定n個形如xi=xj或xi≠xj的變量相等/不等的約束條件,請判定是否可以分別為每一個變量賦予恰當的值,使得上述所有約束條件同時被滿足。例如,一個問題中的約束條件為:x1=x2,x2=x3,x3=x4,x4≠x1,這些約束條件顯然是不可能同時被滿足的,因此這個問題應判定為不可被滿足。
現在給出一些約束滿足問題,請分別對它們進行判定。
輸入輸出格式
輸入格式:從文件prog.in中讀入數據。
輸入文件的第1行包含1個正整數t,表示需要判定的問題個數。註意這些問題之間是相互獨立的。
對於每個問題,包含若幹行:
第1行包含1個正整數n,表示該問題中需要被滿足的約束條件個數。接下來n行,每行包括3個整數i,j,e,描述1個相等/不等的約束條件,相鄰整數之間用單個空格隔開。若e=1,則該約束條件為xi=xj;若?e=0,則該約束條件為xi≠xj;
輸出格式:
輸出到文件 prog.out 中。
輸出文件包括t行。
輸出文件的第 k行輸出一個字符串“ YES” 或者“ NO”(不包含引號,字母全部大寫),“ YES” 表示輸入中的第k個問題判定為可以被滿足,“ NO” 表示不可被滿足。
輸入輸出樣例
輸入樣例#1:2 2 1 2 1 1 2 0 2 1 2 1 2 1 1
NO YES
說明
【樣例解釋1】
在第一個問題中,約束條件為:x1=x2,x1≠x2。這兩個約束條件互相矛盾,因此不可被同時滿足。
在第二個問題中,約束條件為:x1=x2,x1=x2。這兩個約束條件是等價的,可以被同時滿足。
【樣例說明2】
在第一個問題中,約束條件有三個:x1=x2,x2=x3,x3=x1。只需賦值使得x1=x1=x1,即可同時滿足所有的約束條件。
在第二個問題中,約束條件有四個:x1=x2,x2=x3,x3=x4,x4≠x1。由前三個約束條件可以推出x1=x2=x3=x4,然而最後一個約束條件卻要求x1≠x4,因此不可被滿足。
【數據範圍】
【時限2s,內存512M】
題解
並查集+離散化。
先執行所有x=y問題,合並x和y。
再依次執行所有x!=y問題,即查詢x和y是否處於同一集合。如果是,則有x=y且x!=y,不滿足條件。
如果所有的x!=y都得到滿足,這組數據就可以滿足。
註意到i,j範圍為[1,1e9],parent數組開不了這麽大的範圍。又註意到n範圍只有[1,1e5],考慮離散化。
先讀入所有出現的數字,存到一個數組,然後排序並去重。之後操作用到的數字都在這個數組進行二分查找。
時間復雜度O(nlogn)。
註意的坑:
1、最多有n個操作,每個操作有兩個數字,所以並查集的大小應該是n*2。
2、我寫的時候二分查找返回的位置是從0開始的,並查集又寫成從1開始,就WA了一個點,調了好久才發現問題。
#include <algorithm> #include <cstring> #include <iostream> #include <vector> #define maxn 100005 * 2 using namespace std; typedef unsigned long long ullint; namespace djs { int parent[maxn]; inline void init() { for (int i = 0; i < maxn; i++) parent[i] = -1; } inline int find(int x) { int ance = x; while (parent[ance] >= 0) ance = parent[ance]; int at = x; while (parent[at] >= 0) { int fa = parent[at]; parent[at] = ance; at = fa; } return ance; } inline void merge(int x, int y) { x = find(x); y = find(y); if (x == y) return; else { //令x為rank更大的,即parent值更小的 if (parent[x] > parent[y]) swap(x, y); parent[x] += parent[y]; parent[y] = x; } } inline bool is_related(int x, int y) { return find(x) == find(y); } } typedef pair<ullint, ullint> query; vector<query> q, m; //暫存查詢、合並操作 vector<ullint> data; //存儲讀入的所有數據 vector<ullint>::iterator unique_end; //去重後的數據的尾後叠代器 inline int get_pos(ullint v) //二分查找v在data所處的位置 { return lower_bound(data.begin(), unique_end, v) - data.begin(); } int main() { ios::sync_with_stdio(false); int t; cin >> t; while (t--) { using namespace djs; int n; cin >> n; init(); m.clear(); q.clear(); data.clear(); ullint a, b, c; for (int i = 0; i < n; i++) { cin >> a >> b >> c; data.push_back(a); data.push_back(b); switch (c) { case 1: m.push_back(make_pair(a, b)); break; case 0: q.push_back(make_pair(a, b)); break; } } //離散化 sort(data.begin(), data.end()); unique_end = unique(data.begin(), data.end()); //合並 for (int i = 0; i < m.size(); i++) merge(get_pos(m[i].first), get_pos(m[i].second)); //查詢 bool yes = true; for (int i = 0; i < q.size(); i++) { if (is_related(get_pos(q[i].first), get_pos(q[i].second))) { yes = false; break; } } if (yes) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }
【NOI2015】程序自動分析