hdu 5652 India and China Origins 并查集
Posted youmi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 5652 India and China Origins 并查集相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5652
题目大意:n*m的矩阵上,0为平原,1为山。q个询问,第i个询问给定坐标xi,yi,表示i年后这里的平原上会长出山。问第几年以后印度和中国交流会被阻碍
思路:(官方题解)这是一个连通性的问题。你会发现如果将所有操作逆序来看的话就很容易用并查集来处理了。 首先把所有的山峰都加到图中,然后逆序处理每个操作: 对某次操作,在图中删除该位置的山峰,然后判断两个点是否联通,一旦联通就得到了结果。 这里需要对China和India分别新建一个对应的节点。特殊处理代码注释见分晓
/************************************************************** Problem:hdu 5652 User: youmi Language: C++ Result: Accepted Time:93MS Memory:3504K ****************************************************************/ //#pragma comment(linker, "/STACK:1024000000,1024000000") //#include<bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <stack> #include <set> #include <sstream> #include <cmath> #include <queue> #include <deque> #include <string> #include <vector> #define zeros(a) memset(a,0,sizeof(a)) #define ones(a) memset(a,-1,sizeof(a)) #define sc(a) scanf("%d",&a) #define sc2(a,b) scanf("%d%d",&a,&b) #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scs(a) scanf("%s",a) #define sclld(a) scanf("%I64d",&a) #define pt(a) printf("%d\n",a) #define ptlld(a) printf("%I64d\n",a) #define rep0(i,n) for(int i=0;i<n;i++) #define rep1(i,n) for(int i=1;i<=n;i++) #define rep_1(i,n) for(int i=n;i>=1;i--) #define rep_0(i,n) for(int i=n-1;i>=0;i--) #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) #define lson (step<<1) #define rson (lson+1) #define esp 1e-6 #define oo 0x3fffffff #define TEST cout<<"*************************"<<endl using namespace std; typedef long long ll; int n,m,q; const int maxn=500+10; int img[maxn][maxn]; int fa[maxn*maxn]; int s=0,t=n*m+1; struct node { int id; int x,y; void init(int _id,int _x,int _y) { id=_id,x=_x,y=_y; } }p[maxn*maxn]; void init() { for(int i=0;i<=n+1;i++) for(int j=1;j<=m;j++) fa[i*m+j]=i*m+j; /** 将第0排看做起点,第n+1排作为终点, 并分别以对应行最小的1和(n+1)*m+1为代表, 因为我的合并函数是以坐标大小来合并两棵树的 */ for(int j=1;j<=m;j++) img[0][j]=0; for(int j=1;j<=m;j++) img[n+1][j]=0; s=1,t=(n+1)*m+1; fa[s]=s;fa[t]=t; } int get_f(int x) { while(x!=fa[x]) { fa[x]=get_f(fa[x]); x=fa[x]; } return x; } void Union(int x,int y) { int f1=get_f(x); int f2=get_f(y); if(f1>f2) fa[f1]=f2; else fa[f2]=f1; } int kx[]={1,-1,0,0}; int ky[]={0,0,-1,1}; bool isIn(int x,int y) { if(x<0||x>n+1||y<1||y>m) return false; return true; } bool vis[maxn*maxn]; void dfs(int x,int y) { vis[x*m+y]=1; int curx,cury; for(int k=0;k<4;k++) { curx=x+kx[k]; cury=y+ky[k]; if(isIn(curx,cury)&&img[curx][cury]==0) { Union(curx*m+cury,x*m+y); if(!vis[curx*m+cury]) dfs(curx,cury); } } } bool work() { init(); zeros(vis); for(int i=0;i<=n+1;i++) { for(int j=1;j<=m;j++) { if(img[i][j]==0&&!vis[i*m+j]) { dfs(i,j); } } } if(fa[s]==fa[t]) return false; else return true; } void prt() { for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) printf("%d ",img[i][j]); cout<<endl; } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int T_T; scanf("%d",&T_T); for(int kase=1;kase<=T_T;kase++) { sc2(n,m); getchar(); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) img[i][j]=getchar()-‘0‘; getchar(); } sc(q); int x,y; for(int i=1;i<=q;i++) { sc2(x,y); x++,y++; p[i].init(i,x,y); img[x][y]=1; } //prt(); if(!work()) { puts("-1"); continue; } int flag=1; for(int i=q;i>=1;i--) { x=p[i].x,y=p[i].y; img[x][y]=0; get_f(x*m+y); int curx,cury; /** 在恢复为平原时,只需要查看相邻4个点就好了, 因为在第一次dfs的时候把所有为0的点都处理过了 而新出现的0的点只需合并到相邻点的树里就好了 */ for(int k=0;k<4;k++) { curx=x+kx[k]; cury=y+ky[k]; if(isIn(curx,cury)&&img[curx][cury]==0) { Union(curx*m+cury,x*m+y); } } if(get_f(s)==get_f(t)) { printf("%d\n",i); flag=0; break; } } if(flag) puts("0"); } }
以上是关于hdu 5652 India and China Origins 并查集的主要内容,如果未能解决你的问题,请参考以下文章
并查集(逆序处理):HDU 5652 India and China Origins
HDU 5652 India and China Origins 并查集
hdu 5652 India and China Origins 并查集
hdu 5652 India and China Origins 并查集+逆序