P1955 [NOI2015]程序自动分析 离散化学习 lower_bound学习
題目鏈接
https://www.luogu.org/problemnew/show/P1955
題目描述
在實現(xiàn)程序自動分析的過程中,常常需要判定一些約束條件是否能被同時滿足。
考慮一個約束滿足問題的簡化版本:假設(shè)x1,x2,x3...代表程序中出現(xiàn)的變量,給定n個形如xi=xj或xi≠xj的變量相等/不等的約束條件,請判定是否可以分別為每一個變量賦予恰當(dāng)?shù)闹?#xff0c;使得上述所有約束條件同時被滿足。例如,一個問題中的約束條件為:x1=x2,x2=x3,x3=x4,x4≠x1,這些約束條件顯然是不可能同時被滿足的,因此這個問題應(yīng)判定為不可被滿足。
現(xiàn)在給出一些約束滿足問題,請分別對它們進行判定。
輸入輸出格式
輸入格式:從文件prog.in中讀入數(shù)據(jù)。
輸入文件的第1行包含1個正整數(shù)t,表示需要判定的問題個數(shù)。注意這些問題之間是相互獨立的。
對于每個問題,包含若干行:
第1行包含1個正整數(shù)n,表示該問題中需要被滿足的約束條件個數(shù)。接下來n行,每行包括3個整數(shù)i,j,e,描述1個相等/不等的約束條件,相鄰整數(shù)之間用單個空格隔開。若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 輸出樣例#1:? NO YES 輸入樣例#2:? 2 3 1 2 1 2 3 1 3 1 1 4 1 2 1 2 3 1 3 4 1 1 4 0 輸出樣例#2:? YES NO說明
【樣例解釋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,因此不可被滿足。
【數(shù)據(jù)范圍】
【時限2s,內(nèi)存512M】
題目分析
這道題是一個很顯然的并查集,但是看到數(shù)據(jù)范圍
我們竟然需要開一個1e9的數(shù)組!
那么很顯然的會MLE
所以我們要用到離散化
然后就可以了qwq
參考代碼
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 //#define DEBUG(x) cerr << #x << "=" << x << endl 8 const int maxn = 1e5 + 7; 9 10 int n, t, f[maxn], book[maxn * 3]; 11 12 struct node 13 { 14 int x; 15 int y; 16 int e; 17 }a[maxn]; 18 19 bool cmp(node a, node b) 20 { 21 return a.e > b.e; 22 } 23 24 inline void first(int k) 25 { 26 for (int i = 1; i <= k; i++) f[i] = i; 27 } 28 29 int get(int x) 30 { 31 return f[x] == x ? x : f[x] = get(f[x]); 32 } 33 34 int main() 35 { 36 ios::sync_with_stdio(false); 37 cin.tie(0); 38 cin >> t; 39 while (t--) 40 { 41 cin >> n; 42 int tot = -1; 43 int flag = 1; 44 memset(a, 0, sizeof(a)); 45 memset(f, 0, sizeof(f)); 46 memset(book, 0, sizeof(book)); 47 for (int i = 1; i <= n; i++) 48 { 49 cin >> a[i].x >> a[i].y >> a[i].e; 50 book[++tot] = a[i].x; 51 book[++tot] = a[i].y; 52 } 53 sort(book, book + tot); 54 int reu = unique(book, book + tot) - book; 55 for (int i = 1; i <= n; i++) 56 { 57 a[i].x = lower_bound(book, book + reu, a[i].x) - book; 58 a[i].y = lower_bound(book, book + reu, a[i].y) - book; 59 } 60 first(reu); 61 sort(a + 1, a + n + 1, cmp); 62 for (int i = 1; i <= n; i++) 63 { 64 int r1 = get(a[i].x); 65 int r2 = get(a[i].y); 66 if (a[i].e) 67 { 68 f[r1] = r2; 69 } 70 else if (r1 == r2) 71 { 72 cout << "NO" << endl; 73 flag = 0; 74 break; 75 } 76 } 77 if (flag) 78 cout << "YES" << endl; 79 } 80 return 0; 81 }離散化
定義
離散化,把無限空間中有限的個體映射到有限的空間中去,以此提高算法的時空效率。 通俗的說,離散化是在不改變數(shù)據(jù)相對大小的條件下,對數(shù)據(jù)進行相應(yīng)的縮小。例如: 原數(shù)據(jù):1, 999, 100000, 15; 處理后:1, 3, 4, 2; 原數(shù)據(jù):{100, 200},{20, 50000},{1, 400}; 處理后:{3, 4},{2, 6},{1, 5};對于離散化來說主要有三個步驟
一.去重(用unique去重函數(shù))
二.排序
三.二分索引(用lower_bound函數(shù))
1 const int N = 1e5 + 7; 2 3 int t[N], a[N]; 4 5 int main() 6 { 7 std::ios::sync_with_stdio(false); 8 cin.tie(0); 9 cin >> n; 10 for (int i = 1; i <= n; i++) 11 { 12 cin >> a[i]; 13 t[i] = a[i]; 14 } 15 sort(t + 1, t + n + 1); 16 m = unique(t + 1, t + n + 1) - t - 1; 17 for (int i = 1; i <= n; i++) 18 a[i] = lower_bound(t + 1, t + m + 1, a[i]) - t; 19 }在這段代碼中,a[ ]經(jīng)過離散,范圍就變成了m。解釋一下,unique是c++自帶的一個函數(shù),表示對一個數(shù)列去重,然后返回不重復(fù)的元素個數(shù),當(dāng)然在后面要減去首地址。那么這種離散化對于有重復(fù)元素的數(shù)列也可以適用,但是復(fù)雜度會高些。有一種離散化的方式復(fù)雜度會低一些,但是不能處理有重復(fù)元素的數(shù)列,所以在此不再贅述
舉個例子:原數(shù)據(jù):{6, 8, 4, 9, 5, 6, 7, 4},首先排序后得到{4, 4, 5, 6, 6, 7, 8, 9},去重{4, 5, 6, 7, 8, 9},然后原序列就變成了{3, 5, 1, 6, 2, 3, 4, 1}。
lower_bound( )
這里是關(guān)于lower_bound( )和upper_bound( )的常見用法
lower_bound( )和upper_bound( )都是利用二分查找的方法在一個排好序的數(shù)組中進行查找的,這兩個函數(shù)都需要加載頭文件#include<algorithm>
在從小到大的排序數(shù)組中,
lower_bound( begin,end,num):從數(shù)組的begin位置到end-1位置二分查找第一個大于或等于num的數(shù)字,找到返回該數(shù)字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數(shù)字在數(shù)組中的下標。
upper_bound( begin,end,num):從數(shù)組的begin位置到end-1位置二分查找第一個大于num的數(shù)字,找到返回該數(shù)字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數(shù)字在數(shù)組中的下標。
在從大到小的排序數(shù)組中,重載lower_bound()和upper_bound()
lower_bound( begin,end,num,greater<type>() ):從數(shù)組的begin位置到end-1位置二分查找第一個小于或等于num的數(shù)字,找到返回該數(shù)字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數(shù)字在數(shù)組中的下標。
upper_bound( begin,end,num,greater<type>() ):從數(shù)組的begin位置到end-1位置二分查找第一個小于num的數(shù)字,找到返回該數(shù)字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數(shù)字在數(shù)組中的下標。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 //#define DEBUG(x) cerr << #x << "=" << x << endl 8 #define LL long long 9 const int maxn = 1e5 + 10; 10 const int INF = 2 * int(1e9) + 10; 11 12 int cmd(int a, int b) 13 { 14 return a > b; 15 } 16 17 int main() 18 { 19 ios::sync_with_stdio(false); 20 cin.tie(0); 21 int num[6] = {1, 2, 4, 7, 15, 34}; 22 sort(num, num + 6); //按從小到大排序 23 int pos1 = lower_bound(num, num + 6, 7) - num; //返回數(shù)組中第一個大于或等于被查數(shù)的值 24 int pos2 = upper_bound(num, num + 6, 7) - num; //返回數(shù)組中第一個大于被查數(shù)的值 25 cout << pos1 << " " << num[pos1] << endl; 26 cout << pos2 << " " << num[pos2] << endl; 27 sort(num, num + 6, cmd); //按從大到小排序 28 int pos3 = lower_bound(num, num + 6, 7, greater<int>()) - num; //返回數(shù)組中第一個小于或等于被查數(shù)的值 29 int pos4 = upper_bound(num, num + 6, 7, greater<int>()) - num; //返回數(shù)組中第一個小于被查數(shù)的值 30 cout << pos3 << " " << num[pos3] << endl; 31 cout << pos4 << " " << num[pos4] << endl; 32 return 0; 33 }?
轉(zhuǎn)載于:https://www.cnblogs.com/aiyi2000/p/9818985.html
總結(jié)
以上是生活随笔為你收集整理的P1955 [NOI2015]程序自动分析 离散化学习 lower_bound学习的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 接纳强迫,不要过于追求完美,允许自己慢下
- 下一篇: Qt 安装与配置记录