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 并查集+逆序
BestCoder Round #77 (div.2)(hdu5650,hdu5651(逆元),hdu5652(二分),hdu5653(dp))