hdu 5652

Posted xiongtao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 5652相关的知识,希望对你有一定的参考价值。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5652

题目意思:中国和印度之间本来有路连通,但有山在一时刻凸起。把路看成n*m的方格,值为为1则有山,0则没有。

有q个询问,每个询问凸起一个坐标的山。问什么时候路不相通了。

 

思路:并查集,把相邻的点当成一个集合,更新每个集合的左右边界(即这个集合内最左的没左边界,最右的为右边界),再

合并八个方向的集合。直到路封死。

 

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=505;
struct node{
    int l,r;
}a[maxn*maxn];//记录每个集合的左右边界 
int fa[maxn*maxn];//每个点的父结点 
int map[maxn][maxn];
int n,m,q,ans;
bool flag;//标记是否路完全封死 
int dx[]={-1,-1,-1,0,0,1,1,1};
int dy[]={-1,0,1,-1,1,-1,0,1};

int find(int x)//寻找根结点 
{
    if(x==fa[x])
        return x;
    else
        return fa[x]=find(fa[x]);
}

void unionn(int x,int y)//连接两个集合,或者说是树 
{
    x=find(x),y=find(y);
    if(x!=y)
        fa[y]=x;
}

void solve(int i,int j)//判断询问 
{
    for(int k=0;k<8;k++)//八个方向是否有集合可以合并 
    {
        int xx=i+dx[k];
        int yy=j+dy[k];
        if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&map[xx][yy]==1&&find((i-1)*m+j)!=find((xx-1)*m+yy))
        {
            //和下面处理一样 
            a[find((i-1)*m+j)].l=a[find((xx-1)*m+yy)].l=min(a[find((i-1)*m+j)].l,a[find((xx-1)*m+yy)].l);
            a[find((i-1)*m+j)].r=a[find((xx-1)*m+yy)].r=max(a[find((i-1)*m+j)].r,a[find((xx-1)*m+yy)].r);
            unionn((i-1)*m+j,(xx-1)*m+yy);
            if(a[find((i-1)*m+j)].l==1&&a[find((xx-1)*m+yy)].r==m)
                flag=true;
            //cout<<i<<" "<<j<<" "<<a[find((i-1)*m+j)].l<<" "<<a[find((xx-1)*m+yy)].r<<endl;
        }
    }
}
int main()
{
    int t,x,y;
    char s;
    scanf("%d",&t);
    while(t--)
    {
        flag=false;//初始化路没封 
        ans=0;
        scanf("%d%d",&n,&m);
        memset(map,0,sizeof(map));
        for(int i=1;i<=n;i++)
        {
            getchar();
            for(int j=1;j<=m;j++)
            {
                scanf("%c",&s);
                fa[(i-1)*m+j]=(i-1)*m+j;//初始化每个点的父结点是自己(可以理解成自己是一个集合) 
                map[i][j]=s-0;
                if(map[i][j]==1)
                {
                    a[(i-1)*m+j].l=a[(i-1)*m+j].r=j;//初始每个集合的左右边界 
                }
            }
        }
        for(int i=1;i<=n;i++)//找可以合并的集合(或者树) 
        {
            for(int j=1;j<=m;j++)
            {
                if(map[i][j]==1)
                {
                    for(int k=0;k<8;k++)
                    {
                        int xx=i+dx[k];
                        int yy=j+dy[k];
                        if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&map[xx][yy]==1&&find((i-1)*m+j)!=find((xx-1)*m+yy))//寻找条件    
                        {
                            a[find((i-1)*m+j)].l=a[find((xx-1)*m+yy)].l=min(a[find((i-1)*m+j)].l,a[find((xx-1)*m+yy)].l);
                            a[find((i-1)*m+j)].r=a[find((xx-1)*m+yy)].r=max(a[find((i-1)*m+j)].r,a[find((xx-1)*m+yy)].r);
                            //更新最后这个合并集合的左右边界值 
                            unionn((i-1)*m+j,(xx-1)*m+yy);//连接两点 
                            if(a[find((i-1)*m+j)].l==1&&a[find((xx-1)*m+yy)].r==m)//判断路是否已经封死 
                                flag=true;
                            //cout<<i<<" "<<j<<" "<<a[find((i-1)*m+j)].l<<" "<<a[find((i-1)*m+j)].r<<endl;
                        }
                    }
                }
            }
        }
        scanf("%d",&q);
        for(int i=1;i<=q;i++)//询问 
        {
            scanf("%d%d",&x,&y);
            map[x+1][y+1]=1;//记得改变这点的值 
            a[x*m+y+1].l=a[x*m+y+1].r=y+1;
            if(!flag)//没封就一张找 
            {
                ans++;
                solve(x+1,y+1);    
            }
        }
        printf("%d
",ans);
    }
    return 0;
}

 

以上是关于hdu 5652的主要内容,如果未能解决你的问题,请参考以下文章

hdu 5652 India and China Origins 并查集

hdu 5652 India and China Origins 并查集+二分

hdu 5652 India and China Origins 并查集+逆序

HDU 5652 图论之并查集

BestCoder Round #77 (div.2)(hdu5650,hdu5651(逆元),hdu5652(二分),hdu5653(dp))

并查集(逆序处理):HDU 5652 India and China Origins