<題目連結>
題目大意:
給你N個點(編號從0到N-1)和M個關係,要你判斷這個圖的所有點的順序是否可以全部確定.不過對於任意點的關係可能存在A>B或A<B或A=B三種情況,如果A=B的話,那麼就比較他們的編號,編號大的點分數大.(即兩點之間關係如果相等,它們之間的排序也可以確定).
解題分析:
本題要處理等於的情況,單純的拓撲排序不好處理, 因為這些等於的點與其點的關係是相同的,所以用並查集將這些等於的點進行縮點。當然,在判斷衝突的時候,也要考慮到,這些等於的點之間是否會產生衝突,比如開始宣告 A=B ,而後面的宣告又推出A>B的結論,這種情況顯然是不行的,然後就是用拓撲排序判斷當前所有點是否衝突和判斷是否能夠確定唯一的序列。判斷衝突的依據其實就是判斷圖中是否存在環,這個直接根據拓撲排序中依次展開成入度為0的點的個數是否等於總的點數即可,因為如果存在環,那麼環中的點無論如何也不可能展開成入度為0的點。判斷拓撲排序展開後的序列是否唯一則是根據拓撲排序過程中是否在同一時刻有多個入度為0的點來判斷。
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; ; ; int n,m,tot; int fa[N],ind[N],head[N]; ]; int a[M],b[M]; struct Edge{ int to,next; }edges[M]; void addedge(int u,int v){ edges[++tot].to=v,edges[tot].next=head[u]; head[u]=tot;ind[v]++; } int find(int i){ ) return i; return fa[i]=find(fa[i]); } int toposort(){ queue<int> Q; ; //連通分量根數目 ; //入度為0且從Q出佇列的點數 bool order=true; //判斷排列是否唯一 ;i<n;i++)if(find(i)==i){ scc++; ) Q.push(i); //讓入度為0的根節點進入佇列 } while(!Q.empty()){ ) order=false; //如果佇列中同時又多個入度為0的點,則說明該圖不能確定唯一的排序 int u=Q.front();Q.pop(); cnt++; ;i=edges[i].next){ int v=edges[i].to; ) Q.push(find(v)); //入度為0的點入佇列 } } ; //如果在拓撲排序中,入度為0的"點"數<所有的"點"數,說明該圖中必然有環,存在衝突 ; //可確定唯一排序 ; //即不衝突,又不可確定唯一的排序 } int main(){ while(~scanf("%d%d",&n,&m)){ memset(head,-,sizeof(head)); memset(fa,-,sizeof(fa)); memset(ind,,sizeof(ind)); tot=; ; //判斷結果的狀態 ;i<m;i++){ //將所有具有等於關係的進行縮點 scanf("%d%s%d",&a[i],str[i],&b[i]); ]=='='){ int u=a[i], v=b[i]; u=find(u), v=find(v); if(u!=v) fa[u]=v; //用並查集進行縮點 } } ;i<m;i++){ //新增有向邊,且判斷"點"中是否衝突 int u=a[i], v=b[i]; ]!='='){ //判斷該縮點後的"點"中是否存在衝突 ans=-; //衝突 break; } ]=='<') addedge(find(v),find(u)); //新增有向邊 ]=='>') addedge(find(u),find(v)); } ) ans=toposort(); ) printf("CONFLICT\n"); ) printf("UNCERTAIN\n"); ) printf("OK\n"); } }
2018-11-20