hihocoder 1689 推斷大小關係 並查集+dfs
阿新 • • 發佈:2018-12-15
#1689 : 推斷大小關係
時間限制:20000ms
單點時限:2000ms
記憶體限制:256MB
描述
有N個整數A1, A2, ... AN,現在我們知道M條關於這N個整數的資訊。每條資訊是:
Ai < Aj 或者 Ai = Aj
小Hi希望你能從第一條資訊開始依次逐條處理這些資訊。一旦能推斷出A1和AN的大小關係就立即停止。
輸出在處理第幾條時第一次推斷出A1和AN的關係。如果處理完全部M條資訊還是不知道A1和AN的大小關係,輸出-1。
保證M條資訊是沒有矛盾的。
輸入
第一行包含兩個整數N和M。
以下M行每行包含一條資訊Ai < Aj 或者 Ai = Aj。
對於30%的資料,1 ≤ N ≤ 1000, 1 ≤ M ≤ 10000
對於100%的資料,1 ≤ N ≤ 100000, 1 ≤ N ≤ 1000000
輸出
一個整數表示答案。
樣例輸入
5 8 A1 < A3 A3 < A2 A3 < A4 A5 < A2 A1 < A4 A1 < A2 A5 < A1 A5 < A3
樣例輸出
7
思路:從1和n號點開始擴張,如果1號擴張到 n號或者與n相等的點(並查集判斷),則認為關係明確,反之亦然。如果1號擴張的點到n的地盤,擴張終止。擴張路徑只使用一次,每次使用後,刪除該邊。
#include <iostream> #include<bits/stdc++.h> using namespace std; const int MX=1e5+100; int n,m,par[MX],rk[MX],label[MX]; vector<int> g[MX]; void init(int n) { for(int i=0;i<=n;i++) par[i]=i,rk[i]=0,g[i].clear(); memset(label,0,sizeof(label)); } int f(int x) { if(par[x]==x) return x; return par[x]=f(par[x]); } void unite(int x,int y) { x=f(x); y=f(y); if(x==y) return ; if(rk[x]<rk[y]) par[x]=y; else { par[y]=x; if(rk[x]==rk[y]) rk[x]++; } } bool dfs(int u,int num) { if(num==1&&f(u)==f(n) ) return true; if(num==n&&f(u)==f(1) ) return true; if(label[u]!=0&&label[u]!=num) return false; label[u]=num; for(int i=0;i<g[u].size();i++) { int v=g[u][i]; if(label[v]!=num) if(dfs(v,num)) return true; } g[u].clear(); return false; } int main() { while(cin>>n>>m) { init(n); label[1]=1;label[n]=n; int ans=-1; for(int i=0;i<m;i++) { int x,y; char c; scanf("\nA%d %c A%d",&x,&c,&y); if(ans>0) continue; if(c=='=') { unite(x,y); g[x].push_back(y); if(label[x]==1 ||label[x]==n) if(dfs(x,label[x])) ans=i+1; g[y].push_back(x); if(label[y]==1||label[y]==n) if(dfs(y,label[y])) ans=i+1; } else { g[x].push_back(y); if( label[x] == 1 || label[x]==n) if(dfs(x,label[x])) ans=i+1; } } cout<<ans<<endl; } return 0; }