hihocoder 1689 推断大小关系 并查集+dfs

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值