P1141 01迷宫

题目描述

有一个仅由数字 0 与 1组成的  n×n 格迷宫。若你位于一格0上,那么你可以移动到相邻 4 格中的某一格 1 上,同样若你位于一格1上,那么你可以移动到相邻 4 格中的某一格 0 上。

你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

输入输出格式

输入格式:

 

第 11 行为两个正整数 n,m 。

下面 n 行,每行 n 个字符,字符只可能是 0 或者 1 ,字符之间没有空格。

接下来 m行,每行 2个用空格分隔的正整数 i,j ,对应了迷宫中第 i 行第 j列的一个格子,询问从这一格开始能移动到多少格。

 

输出格式:

 

m 行,对于每个询问输出相应答案。

 

输入输出样例

输入样例#1: 复制

2 2
01
10
1 1
2 2

输出样例#1: 复制

4
4

说明

所有格子互相可达。

对于 20% 的数据, n≤10 ;

对于 40% 的数据, n≤50 ;

对于 50% 的数据, m≤5;

对于 60% 的数据, n≤100,m≤100 ;

对于 100% 的数   n≤1000,m≤100000 。

思路

    一开始想的是bfs,不过提交代码之后,发现超时了,仔细一想,既然一个位置能到达另一个位置,那么反过来一样能达到,因此,可以把一个位置能到达的所有位置看成是一个连通块,在一个连通块内,任何位置所到达的格子一样,这样一来,把连通块的位置都进行标记,再搜索没标记的,再看成一个连通块,直至所有位置搜索完

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<map>
using namespace std;

const int MAXN=1e3+10;
string s[MAXN];
int d[4][2]={0,1,0,-1,1,0,-1,0};
int vis[MAXN][MAXN];
int f[MAXN][MAXN];
int b[1000005][2];
struct node
{
    int x,y;
};
int res,n,m;
void bfs(int x,int y)   // 常规bfs
{
    queue<node> que;
    node e1,e2;
    e1.x=x,e1.y=y;
    res++;
    b[res][0]=x;    // 对经过的位置进行记录
    b[res][1]=y;
    que.push(e1);
    vis[e1.x][e1.y]=0;   //标记
    while(que.size()){
        e1=que.front();que.pop();
        for(int i=0;i<4;i++){
            e2.x=e1.x+d[i][0];
            e2.y=e1.y+d[i][1];
            if(e2.x>=0&&e2.x<n&&e2.y>=0&&e2.y<n&&vis[e2.x][e2.y]){
                if(s[e1.x][e1.y]!=s[e2.x][e2.y]){
                    res++;
                    b[res][0]=e2.x;    // 记录
                    b[res][1]=e2.y;
                    que.push(e2);
                    vis[e2.x][e2.y]=0;
                }
            }
        }
    }
}
int main()
{
    int x,y;
    cin >> n>>m;
    for(int i=0;i<n;i++)
        cin>>s[i];
    memset(vis,1,sizeof(vis));
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            if(vis[i][j]){        //搜索未经过的位置
                vis[i][j]=0;
                res=0;
                bfs(i,j);
                for(int k=1;k<=res;k++)    // 把一次搜索所经过的路径看成是一个连通块
                    f[b[k][0]][b[k][1]]=res;  //连通块内所能到达的格子都一样,即联通块的大小
            }
    while(m--){
        cin>>x>>y;
        cout<<f[x-1][y-1]<<endl;      //直接输出
    }
    return 0;
}

这一题,也可以用dfs做,思路差不多,代码更加简洁

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<map>
using namespace std;

const int MAXN=1e3+10;
string s[MAXN];
int d[4][2]={0,1,0,-1,1,0,-1,0};
int vis[MAXN][MAXN],f[MAXN][MAXN];
int b[1000005][2];
int res,n;
void dfs(int x,int y)
{
    res++;
    b[res][0]=x,b[res][1]=y;
    for(int i=0;i<4;i++){
        int nx=x+d[i][0],ny=y+d[i][1];
        if(nx>=0&&nx<n&&ny>=0&&ny<n&&vis[nx][ny]&&s[nx][ny]!=s[x][y]){
            vis[nx][ny]=0;
            dfs(nx,ny);
        }
    }
}
int main()
{
    int x,y,m;
    cin >> n>>m;
    for(int i=0;i<n;i++)
        cin>>s[i];
    memset(vis,1,sizeof(vis));
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            if(vis[i][j]){
                vis[i][j]=0;
                res=0;
                dfs(i,j);
                for(int k=1;k<=res;k++)
                    f[b[k][0]][b[k][1]]=res;
            }
    while(m--){
        cin>>x>>y;
        cout << f[x-1][y-1]<<endl;
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值