2017百度之星初赛:A-1002. 数据分割(并查集+set)
數據分割
? ?Accepts: 102 ? ?Submissions: 1332 ?Time Limit: 2000/1000 MS (Java/Others) ? ?Memory Limit: 32768/32768 K (Java/Others) Problem Description小w來到百度之星的賽場上,準備開始實現一個程序自動分析系統。
這個程序接受一些形如x_i = x_jx?i??=x?j???或?x_i \neq x_jx?i??≠x?j???的相等/不等約束條件作為輸入,判定是否可以通過給每個 w 賦適當的值,來滿足這些條件。
輸入包含多組數據。 然而粗心的小w不幸地把每組數據之間的分隔符刪掉了。 他只知道每組數據都是不可滿足的,且若把每組數據的最后一個約束條件去掉,則該組數據是可滿足的。
請幫助他恢復這些分隔符。
Input第11行:一個數字LL,表示后面輸入的總行數。
之后LL行,每行包含三個整數,i,j,ei,j,e,描述一個相等/不等的約束條件,若e=1e=1,則該約束條件為x_i = x_jx?i??=x?j???,若e=0e=0,則該約束條件為?x_i \neq x_jx?i??≠x?j???。
i,j,L \leq 100000i,j,L≤100000
x_i , x_j \leq Lx?i??,x?j??≤L
Output輸出共T+1T+1行。
第一行一個整數TT,表示數據組數。
接下來TT行的第ii行,一個整數,表示第i組數據中的約束條件個數。
Sample Input 6 2 2 1 2 2 1 1 1 1 3 1 1 1 3 1 1 3 0 Sample Output 1 6
既然題目說每組數據把最后一個約束條件去掉就合理
那么只要將這L組約數條件從前往后遍歷一下就好了
初始化一個空集,將約束條件一個一個加入集合里,當加到某個約束條件之后不合理了,
就說明這是最后一個約束條件,把它刪掉,之后集合里剩下的約束條件個數就是當前答案
然后清空集合,繼續
主要是如何判斷它突然就不合理了
很顯然相等是有傳遞性的,也就是說這個并查集就能輕松搞定
但是不相等不具有傳遞性
那么考慮暴力,開100000個set,set[x]里面存的是所有與x不相等的數
那么有題解:
每個約束x≠y,只要看x和y是否在同一個并查集里就好,如果在同一并查集說明不合理
否則合理,set[x].insert(y), set[y].insert(x)
每個約束x==y,看set[x]里是否有y,set[y]里是否有x,如果有則不合理,否則將x和y加入并查集
但是這樣是錯的,上面紫色的部分錯了!
因為有這種情況:x和y相等,x和z不相等,那么y和z肯定也不相等
也就是說只要z和x不相等,那么和x在同一個并查集合里的所有數都和z不相等
這個時候要將x并查集里所有的數都insert(z),肯定超時
所以只能將所有的并查集歸為一類,set[x]里面存的是所有與x并查集里面的數不相等的數
然后并查集合并的時候set跟著一起合并
因為最多只會有L對約束關系,出現最多2L個數,而并查集是O(n)的
所以處理的好的話復雜度是基本上線性的,只有額外set的復雜度
不要輕易memset
#include<stdio.h> #include<set> #include<string.h> #include<algorithm> using namespace std; set<int> un[100005], st; int cnt, ufs[100005], ans[100005]; int Find(int x) {if(ufs[x]==-1)return x;return ufs[x] = Find(ufs[x]); } void Union(int x, int y) {set<int>::iterator it;if(x==y)return;if(un[x].size()>un[y].size())swap(x, y);for(it=un[x].begin();it!=un[x].end();it++){un[*it].erase(x);un[*it].insert(y);un[y].insert(*it);}ufs[x] = y; } int main(void) {int L, i, x, y, t, t1, t2, sum;set<int>::iterator it;scanf("%d", &L);memset(ufs, -1, sizeof(ufs));sum = 0;while(L--){sum++;scanf("%d%d%d", &x, &y, &t);st.insert(x);st.insert(y);t1 = Find(x), t2 = Find(y);if(t==1){if(t1==t2 || un[t1].count(t2)==0)Union(t1, t2);else{ans[++cnt] = sum;sum = 0;for(it=st.begin();it!=st.end();it++){un[*it].clear();ufs[*it] = -1;}st.clear();}}else{if(t1==t2){ans[++cnt] = sum;sum = 0;for(it=st.begin();it!=st.end();it++){un[*it].clear();ufs[*it] = -1;}st.clear();}else{un[t1].insert(t2);un[t2].insert(t1);}}}printf("%d\n", cnt);for(i=1;i<=cnt;i++)printf("%d\n", ans[i]);return 0; }
總結
以上是生活随笔為你收集整理的2017百度之星初赛:A-1002. 数据分割(并查集+set)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个程序教你花式示爱 1——波动心形线
- 下一篇: 华为荣耀+T8950