zoukankan      html  css  js  c++  java
  • 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");
        }
    }
    不为失败找借口,只为成功找方法
  • 相关阅读:
    494 Target Sum 目标和
    493 Reverse Pairs 翻转对
    492 Construct the Rectangle 构建矩形
    491 Increasing Subsequences 递增子序列
    488 Zuma Game 祖玛游戏
    486 Predict the Winner 预测赢家
    485 Max Consecutive Ones 最大连续1的个数
    483 Smallest Good Base
    Django Form组件
    Django Auth组件
  • 原文地址:https://www.cnblogs.com/youmi/p/5343336.html
Copyright © 2011-2022 走看看