B - Gremlins attack! Gym - 102785B(并查集拓展)

There’s an emergency in a county-level American town. Gremlins have scattered around the town and thus the rest of the world is in danger, as, at least, one of them seems to have left the town. Special intelligence services are currently restoring the course of events and trying to identify the earliest moment when it could happen.

The town is represented in the form of a square checkered board of size N×N. Each cell represents a single house. Gremlins are, typically, afraid of bright light and therefore tend to hide in darkness. Furthermore, as people go to bed, the lights in the houses are going out. Gremlins can move horizontally and vertically from one house, where the light is off, to another. As soon as they reach the house which is on the border of the town, they escape from the town.

You have reliable data about which houses gremlins occupied in the beginning, as well as the history of turning the lights off in the houses. You need to display number of the house in history, from which after turning the light off, at least, one gremlin could escape from the town. If gremlins can escape from the town immediately, type 0. The numbering of houses in history starts with one.

Input
In the first line, three integers are entered, separated by spaces, 1<N<=500, 1<=M<=N2, 1<=K<=N2, where N determines the size of the city, M is the number of houses in which gremlins are located at the beginning, K is the size of the history of turning off lights in the houses.

Then there are M lines, each of which contains a pair of numbers 0<=xi,yi<N, specifying the coordinates of the houses where gremlins are located at the beginning. After that, there follow K lines, each of which contains a pair of numbers 0<=xj,yj<N, specifying the coordinates of the houses in which the light is turned off.

Output
The single number from 0 to K, which sets the number of the house, in which after turning off the light, at least, one gremlin had the opportunity to escape from the town.

Examples
Input
3 1 3
1 1
0 0
0 1
0 2
Output
2
Input
5 2 5
0 1
4 1
0 0
1 1
2 2
3 3
4 4
Output
0
Input
4 2 3
1 1
1 2
2 0
3 1
1 3
Output
3
Input
5 2 6
1 1
3 3
1 2
1 3
2 3
3 0
3 1
2 1
Output
6
Input
7 6 7
1 4
1 1
2 3
3 1
4 4
5 2
0 4
2 4
3 4
1 0
2 1
5 1
5 0
Output
1
Note
The input data guarantee that the escape could have been made.

这道题也可以用dfs做,并且也挺快, 但是这种可以用并查集的题一般用并查集会更快一些,尤其是优化过后的, 这次写博客就是用了并查集(有改变),特此来记录一下这样的做法

这道题的大意就是给一个n*n的图,里面有m个小精灵他们想到边界去,但是只能走关了灯的地方,现在给你k个灯关闭的位置,请问在关第几盏灯时至少有一个小精灵能出去(保证有解)如果开始时就有小精灵在边界,则输出零。
这道题可以把所有关了灯的位置能连起来的地方都用并查集连起来,只要其中一个满足在边上就意味着可以出去,只要有其中一个旁边有小精灵就意味着有人能走 然后一个一个的把点加进去,看从哪个点开始某个集合旁边是出口并且旁边有小精灵
而当实现时会有两个点需要注意,1。这是一个二维的地图,而不是一维的,并查集的储存是个问题,2.怎么才能表示某个集合里有小精灵或者可以走出去。
对这两个点的实现就是我认为比较精妙的地方,第一点比较好解决,只要把第一行的点编号为0~500,第二行的点编号为 501~1000,也就是坐标x×500+y即可(代码中因为一些玄学的原因实际上乘的是501) 至于第二点,我们可以设另外两个不属于此集合点,比如502×502+1 和502×502+2,,一个表示旁边是否有小精灵,另一个表示旁边有没有出口 当这两个点在一个集合里面的时候即为满足条件。注意特判0
上代码

#include <iostream>
#include <bits/stdc++.h>

using namespace std;
const int $=502;
const int ac=502*502+1;//小精灵代表的点
const int bc=502*502+2;//出口代表的点
int a[$][$];//地图
int pre[$*$+5];//并查集集合
int n, m, k;
int nextt[][2]= {0,1, 1,0, 0,-1, -1,0};//只有上下左右四个方向
int findd(int x)
{
    if(pre[x]!=x) return pre[x]=findd(pre[x]);
    else return x;
}
void unionn(int x, int y)
{
    int xx=findd(x);
    int yy=findd(y);
    if(xx!=yy)
        pre[xx]=yy;
}
void prework()
{
    memset(a, 0, sizeof(a));
    for(int i=0; i<$*$+5; i++)
    {
        pre[i]=i;
    }
}
void make(int u, int v)
{
    if(u==0||v==0||u==n-1||v==n-1)
    {
        unionn(u*501+v, bc);
    }
    for(int i=0; i<4; i++)
    {
        int xx=u+nextt[i][0];
        int yy=v+nextt[i][1];
        if(xx<0||yy<0||xx>=n||yy>=n) continue;
        if(a[xx][yy]==2)
        {
            unionn(xx*501+yy, u*501+v);
        }
        if(a[xx][yy]==1)
        {
            unionn(u*501+v, ac);
        }
    }
}
int main()
{
//    for(int i=0;i<4;i++)
//        printf("%d %d\n", nextt[i][0], nextt[i][1]);
    ios::sync_with_stdio(0);
    prework();
    cin>>n>>m>>k;
    int ans=-1;
    for(int i=0; i<m; i++)
    {
        int u, v;
        cin>>u>>v;
        a[u][v]=1;
        if(u==0||v==0||u==n-1||v==n-1)
            ans=0;
    }
    for(int i=0; i<k; i++)
    {
        int u, v;
        cin>>u>>v;
        a[u][v]=2;
        if(ans!=-1) continue;
        make(u, v);
        if(findd(ac)==findd(bc))
        {
            ans=i+1;
        }
    }
    cout<<ans<<"\n";
    return 0;
}

另外因为地图小, 我直接用邻接矩阵存的,如果大了可以用map+pair,在这道题上用起来是一样的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值