#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;
}