1. 程式人生 > >hdu 5652

hdu 5652

include 結點 print main 改變 long end lse ems

題目鏈接: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\n",ans); } return 0; }

hdu 5652