India and China Origins---hdu5652(二分 + bfs)或者(并查集)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5652

题意:

很久以前,中国和印度之间并没有喜马拉雅山相隔,两国的文化交流很频繁。随着喜马拉雅山海拔逐渐增加,两个地区的交流也越来越少,最终没有了来往。
假设当时的地形和我画的一样,蓝色部分代表海洋,而且当时人们还没有发明轮船。黄色部分代表沙漠,而且沙漠上经常有野鬼散步,所以人们不敢到沙漠中行走。黑色的格子表示山峰,这些山峰都无比高大,所以人无法穿过。白色格子代表平原,
人可以在平原上自由行走。人每次可以向相邻的四个格子走动。 此外,我们的考古学家发现还有一些山峰会逐渐形成,通过研究发现,位置在 (x, y)(x,y) (保证该位置之前没有山峰)的地方在 ii 年后出现了山峰。现在给你若干个位置出现山峰的时间,
你可以计算出中国和印度之间的联系最早被彻底切断的时间吗?

 

输入描述
多组测试数据, 第一行为组数T(T10)。每组测试数据第一行包含两个数 N, M (1N,M500), 表示地图的大小。接下来 NN 行长度为 MM 的 0101 字符串。00代表白色格子,11 代表山峰。接下来有 Q(1QN×M) 行,
i(1iQ) 两个整数 (x,y),0x<N,0y<M 表示在第 ii 年 (x,y) 出现了一座山峰。
输出描述
对于每组测试数据,输出一个数, 表示两国最早失联的时间。如果最终两国之间还有联系则输出 -1


可以二分所有的时间,找到第一个让上下不连通的那个时间点;时间复杂度较高;

#include <stdio.h>
#include <algorithm>
#include<string.h>
#include<queue>
using namespace std;

#define MOD 1000000007
#define N 550
typedef long long LL;


char G[N][N];
int m, n, x[N*N], y[N*N];

int dir[4][2]= { {1, 0}, {-1,0}, {0, 1}, {0, -1} };


struct node
{
    int x, y;
};

int bfs(int x, int y, char Maps[][N])
{
    node p, q;
    queue<node> Q;
    p.x = x, p.y = y;
    Q.push(p);

    int vis[N][N];

    memset(vis, 0, sizeof(vis));
    vis[x][y] = 1;

    while(Q.size())
    {
        p = Q.front();
        Q.pop();

        if(p.x == n-1)///可以连通;
            return 1;

        for(int i=0; i<4; i++)
        {
            q.x = p.x+dir[i][0];
            q.y = p.y+dir[i][1];

            if(q.x>=0 && q.x<n && q.y>=0 && q.y<m && Maps[q.x][q.y]=='0' && !vis[q.x][q.y])
            {
                vis[q.x][q.y] = 1;
                Q.push(q);
            }
        }
    }
    return 0;
}

int Judge(char Maps[][N])
{
    for(int i=0; i<m; i++)
    {
        if(Maps[0][i]=='0')///枚举所有第一行可以走的点;
        {
            if( bfs(0, i, Maps) )///如果可以连通;
                return 1;
        }
    }
    return 0;
}

void Init(char Map[][N], int Mid)
{
    memset(Map, 0, sizeof(Map));

    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            Map[i][j] = G[i][j];

    for(int i=1; i<=Mid; i++)
        Map[x[i]][y[i]] = '1';
}

int main()
{
    int T, k;

    scanf("%d", &T);

    while(T--)
    {
        scanf("%d %d", &n, &m);

        for(int i=0; i<n; i++)
            scanf("%s", G[i]);

        scanf("%d", &k);

        for(int i=1; i<=k; i++)
            scanf("%d %d", &x[i], &y[i]);

        int L = 1, R = k, Mid = 0;

        char Map[N][N];

        while(L <= R)
        {
            Mid = (L+R) / 2;

            Init(Map, Mid);///重新构造地图,判断第Mid年加上是否连通;

            if( !Judge(Map) )///不连通;
                R = Mid - 1;
            else
                L = Mid + 1;
        }
        if(L > k) L = -1;

        printf("%d\n", L);
    }
    return 0;
}
/*
15
3 4
1100
0001
0000
2
0 3
2 0
*/
View Code

重新做了下一这道题;发现是可以用并查集做的,时间复杂度相当于O(Q)的一共有n*m个点,
我们可以编号为1-n*m我们把中国的区域地方看成编号0,印度的区域地方看成n*m+1;
然后把所有的山峰放上去,把所有(i,j)位置能到达的点(xi, yi)建立到一个集合中去;
倒着消除山峰,建立集合,当发现0和n*m+1在一个集中时,说明是当前山峰阻止了两国,答案就是当前山峰的年份;

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<math.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 550
#define PI 4*atan(1.0)
#define mod 110119
#define met(a, b) memset(a, b, sizeof(a))
typedef long long LL;

int f[N*N], n, m, x[N*N], y[N*N];
char G[N][N];
int dir[4][2] = {{-1,0},{1,0},{0,1},{0,-1}};

int Find(int x)
{
    if(x!=f[x])
        f[x] = Find(f[x]);
    return f[x];
}

void Union(int a, int b)
{
    int pa = Find(a);
    int pb = Find(b);
    if(pa != pb)
        f[pa] = pb;
}

int Cul(int X, int Y)
{
    if(Y<0 || Y>=m) return -1;
    if(X == -1) return 0;
    if(X == n) return n*m+1;
    if(G[X][Y] == '1') return -1;
    return X*m + Y + 1;
}

int main()
{
    int T, q;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d", &n, &m);

        for(int i=0; i<n; i++)
            scanf("%s", G[i]);

        scanf("%d", &q);
        for(int i=1; i<=q; i++)
        {
            scanf("%d %d", &x[i], &y[i]);
            G[x[i]][y[i]] = '1';
        }

        for(int i=0; i<=n*m+5; i++)///初始化f;
            f[i] = i;

        for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
        {
            if(G[i][j] == '1') continue;
            int num1 = Cul(i, j);///找到当前点的编号;
            for(int k=0; k<4; k++)///与相邻的四点建立关系;
            {
                int p = i + dir[k][0];
                int q = j + dir[k][1];
                int num2 = Cul(p, q);
                if(num2 != -1)///-1代表不能联合;
                    Union(num1, num2);
            }
        }
        for(int i=q; i>0; i--)
        {
            G[x[i]][y[i]] = '0';///消除当前山峰;建立联合;
            int num1 = Cul(x[i], y[i]);
            for(int k=0; k<4; k++)
            {
                int p = x[i] + dir[k][0];
                int q = y[i] + dir[k][1];
                int num2 = Cul(p, q);
                if(num2 != -1)
                    Union(num1, num2);
            }
            if(Find(0) == Find(m*n+1))///当两点在一个集合中时;找到答案;
            {
                printf("%d\n", i);
                break;
            }
        }
    }
    return 0;
}
View Code

 

 

 

 
posted @ 2016-03-30 16:51  西瓜不懂柠檬的酸  Views(151)  Comments(0)    收藏  举报
levels of contents