hdu5652 India and China Origins(并查集)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5652

题目大意:

在n*m的矩阵里面,放值为1的山峰。当山峰连起来能够封锁整个m列的时候,问最早是什么时候。

范围:

n,m<=500,Q<=n*m。

思路:

可以用并查集存下每个点能向左延伸的距离和向右延伸的距离。当有一个点为1的时候,看他8个方向是否有为1的山峰,如果有就将他们并入同一个集合,然后更新他们的最左和最右。当能够封锁的时候,就是答案。

代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,x[250500],y[250500];
struct node{
    int l,r,num;
}p[5500005];
char  s[505][505];
void init()
{
    int i,j;
    for(i=0;i<=505;i++)
    for(j=0;j<=505;j++)
    {
        p[i*1000+j].l=j;
        p[i*1000+j].r=j;
        p[i*1000+j].num=1000*i+j;  //初始化将点化为数。
    }
    return ;
}
int findroot(int x)
{
    int r=x;
    while(r!=p[r].num)
    r=p[r].num;
    int i=x,j;
 
   while(i!=r)
    {
        j=p[i].num;
        p[i].num=r;
        i=j;
    }
    return r;
}
int join(int x,int y)
{
    int fx,fy;
    fx=findroot(x);
    fy=findroot(y);
    if(fx<fy){
        p[fy].num=fx;
        int mi,ma;
        mi=min(min(p[y].l,p[fx].l),min(p[x].l,p[fy].l));
        ma=max(max(p[y].r,p[fx].r),max(p[x].r,p[fy].r));
        p[fy].l=p[x].l=p[y].l=p[fx].l=mi;
        p[fy].r=p[x].r=p[y].r=p[fx].r=ma;
        return fx;
    }
    else {
    p[fx].num=fy;
    int mi,ma;
        mi=min(min(p[y].l,p[fx].l),min(p[x].l,p[fy].l));
        ma=max(max(p[y].r,p[fx].r),max(p[x].r,p[fy].r));
        p[fy].l=p[x].l=p[y].l=p[fx].l=mi;
        p[fy].r=p[x].r=p[y].r=p[fx].r=ma;
    return fy;
    }
}
void judge(int x,int y)
{
    int a,b;
    if(s[x][y+1]==1&&y+1<=m){
        a=x*1000+y;
        b=x*1000+y+1;
        int mi=join(a,b);
    }
    if(s[x+1][y+1]==1&&x+1<=n&&y+1<=m){
        a=x*1000+y;
        b=(x+1)*1000+y+1;
        int mi=join(a,b);
    }
    if(s[x+1][y]==1&&x+1<=n){
        a=x*1000+y;
        b=(x+1)*1000+y;
        int mi=join(a,b);
    }
    if(s[x+1][y-1]==1&&x+1<=n&&y-1>0)
    {
         a=x*1000+y;
        b=(x+1)*1000+y-1;
        int mi=join(a,b);
    }
    if(s[x][y-1]==1&&y-1>0)
    {
         a=x*1000+y;
        b=(x)*1000+y-1;
        int mi=join(a,b);
    }
    if(s[x-1][y-1]==1&&x-1>0&&y-1>0)
    {
         a=x*1000+y;
        b=(x-1)*1000+y-1;
        int mi=join(a,b);
    }
     if(s[x-1][y]==1&&x-1>0){
          a=x*1000+y;
        b=(x-1)*1000+y;
        int mi=join(a,b);
     }
     if(s[x-1][y+1]==1&&x-1>0&&y+1<=m)
     {
         a=x*1000+y;
         b=(x-1)*1000+y+1;
         int mi=join(a,b);
     }
}
int main()
{
    int T,i,j,k,Q;    
    scanf("%d",&T);
    while(T--)
    {
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        for(i=0;i<505;i++)
        for(j=0;j<505;j++)
        s[i][j]=0;
        init();
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            cin>>s[i][j];
            s[i][j]-='0';
        }
        int ff=0;
        for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            if(s[i][j]==1){
                judge(i,j);
                int aa=i*1000+j;
                aa=findroot(aa);
                if(p[aa].r-p[aa].l==m-1){
                    ff=1;
                    break;
                }
            }
        }
        scanf("%d",&Q);
        for(i=1;i<=Q;i++)
        scanf("%d%d",&x[i],&y[i]);
        if(ff){
            printf("0\n");
            continue;
        }
        int f=0;
        for(i=1;i<=Q;i++)
        {
            s[x[i]+1][y[i]+1]=1;
            judge(x[i]+1,y[i]+1);
            int fx;
            fx=findroot((x[i]+1)*1000+y[i]+1);
            if(p[fx].r-p[fx].l==m-1){
                printf("%d\n",i);
                f=1;
                break;
            }
        }
        if(f==0)printf("-1\n");
    }
}
/*
3 3
010
000
010
5
0 0
1 0
0 2
1 1
2 0
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值