程序自動分析(NOI2015)(洛谷P1955)題解

原題:node

在實現程序自動分析的過程當中,經常須要斷定一些約束條件是否能被同時知足。ui

考慮一個約束知足問題的簡化版本:假設x1,x2,x3...表明程序中出現的變量,給定n個形如xi=xj或xi≠xj的變量相等/不等的約束條件,請斷定是否能夠分別爲每個變量賦予恰當的值,使得上述全部約束條件同時被知足。例如,一個問題中的約束條件爲:x1=x2,x2=x3,x3=x4,x4≠x1,這些約束條件顯然是不可能同時被知足的,所以這個問題應斷定爲不可被知足。spa

如今給出一些約束知足問題,請分別對它們進行斷定。code

輸入輸出格式

輸入格式:blog

從文件prog.in中讀入數據。字符串

輸入文件的第1行包含1個正整數t,表示須要斷定的問題個數。注意這些問題之間是相互獨立的。get

對於每一個問題,包含若干行:string

第1行包含1個正整數n,表示該問題中須要被知足的約束條件個數。接下來n行,每行包括3個整數i,j,e,描述1個相等/不等的約束條件,相鄰整數之間用單個空格隔開。若e=1,則該約束條件爲xi=xj;若�e=0,則該約束條件爲xi≠xj;it

輸出格式:io

輸出到文件 prog.out 中。

輸出文件包括t行。

輸出文件的第 k行輸出一個字符串「 YES」 或者「 NO」(不包含引號,字母所有大寫),「 YES」 表示輸入中的第k個問題斷定爲能夠被知足,「 NO」 表示不可被知足。

 


帶權並查集。

有點相似於食物鏈,點這裏。沒作過的同窗能夠去作一下加深理解。

咱們用0和1表明這個數和根節點相同或者不一樣,當矛盾時即這句話是假話。

因而快樂地寫完代碼過樣例,交了上去:

 

黑人問號臉(???)

因而下載了數據,發現了這個問題:

若是按照正常的順序處理,當給出這樣的數據時:

a≠b,b≠c,c≠a

根據咱們的理論,0表明相同,1表明不相同,前兩個數據能夠得:a爲0,b爲1,c爲0,那麼當c≠a時,推出矛盾。

這樣作顯然是錯誤的。前兩個條件並非第三個結論的充要條件。輕易能夠舉出反例:

a = 1,b = 2,c = 3

那麼咱們最好的作法即是先把全部的相等條件加入到同一個並查集中,再去處理不相等的狀況,若是a,b在同一個並查集中,那麼顯然不成立。若是不在,就能夠知足。

上代碼:

 

#include<cstdio> #include<algorithm> #include<string> #include<cstring>
#define N 1000005
using namespace std; int n; int f[N]; int g[N]; bool flag; int find(int x) { if(f[x]==x) { return f[x]; } int fx = find(f[x]); g[x] = (g[f[x]]+g[x])%2; return f[x] = fx; } struct node { int x; int y; int a; int num; int p; }nd[N+N+N]; void uion(int x,int y,int a) { int fx = find(x); int fy = find(y); if(fx!=fy) { f[fy] = fx; if(a==1) { g[fy] = (g[x]-g[y]+2)%2; }else { g[fy] = (g[x]-g[y]+2+1)%2; } } } int cmp(node a,node b) { return a.p<b.p; } void init() { memset(g,0,sizeof(g)); memset(nd,0,sizeof(nd)); flag = 0; scanf("%d",&n); for(int i = 1;i<=n;i++) { scanf("%d%d%d",&nd[i].p,&nd[i+n].p,&nd[i+n+n].a); nd[i].num = i; nd[i+n].num = i; } } void disperse() { sort(nd+1,nd+1+n+n,cmp); int cnt = 1; for(int i = 1;i<=n+n;i++) { if(!nd[nd[i].num].x) { nd[nd[i].num].x = cnt; }else { nd[nd[i].num].y = cnt; } if(nd[i+1].p!=nd[i].p) { cnt++; } } for(int i = 1;i<=n;i++) { nd[i].a = nd[i+n+n].a; } for(int i = 1;i<=cnt;i++) { f[i] = i; } } void solve() { for(int i = 1;i<=n;i++) { if(nd[i].a==1) { uion(nd[i].x,nd[i].y,nd[i].a); } } for(int i = 1;i<=n;i++) { if(nd[i].a==0) { int fx = find(nd[i].x); int fy = find(nd[i].y); if(fx==fy) { printf("NO\n"); flag = 1; return ; } } } } int main() { int t; scanf("%d",&t); while(t--) { init(); disperse(); solve(); if(flag==0) { printf("YES\n"); } } } /* 第三組數據奉上 1 9 24 234 1 2837 1 1 242 78 0 23 1 1 223 977 0 254 76 1 235 877 0 235 987 0 877 987 0 */
相關文章
相關標籤/搜索