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
",a)
#define ptlld(a) printf("%I64d
",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
",i);
                flag=0;
                break;
            }
        }
        if(flag)
            puts("0");
    }
}
不为失败找借口,只为成功找方法
原文地址:https://www.cnblogs.com/youmi/p/5343336.html