P1141 01迷宫

题目描述

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

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

输入输出格式

输入格式:
输入的第1行为两个正整数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。

TJ:宽搜好题,
0 1
1 0
如果这里面一个位置都能到达其他位置,那么这个集合中任一位置都能到达其他位置。

0 — > 1
|     |
v     v
1     0

因为是0可以到达1,1也可以到达0,因此是双连通即:

01
|    |
1    0

因此,只要求出连通块内有几个元素,那么这个集合中的所有格子能移动到多少个格子的数量都是几。

问题是如何求连通块内有几个元素呢?实际上就是宽搜的尾指针数。想一想为什么?
然后类似于记忆化搜索,标记一下是否走过,走过的放进表里(布尔数组),搜索的时候先查询,没有再搜索。搜索的时候先记录,再返回。

代码如下:注意数组大小,否则MLE

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,t,b[1005][1005],c[1005][1005],ax[1000000],ay[1000000],mk[1000000],x,y,ans[1005][1005];
char a[1005][1005];
int mx[4]={0,0,1,-1},
    my[4]={1,-1,0,0};
void bfs(int x,int y)
{
    int head=1,tail=1;
    ax[1]=x,ay[1]=y,b[x][y]=1;//b[]忘写了 
    while(head<=tail)//这样写规范,也亦理解,循环体里面的tail 是几就表示进行到几了。 
    {
        for(int i=0;i<4;i++)
        {
            int xx=ax[head]+mx[i];
            int yy=ay[head]+my[i];
            if(xx>=1 && xx<=n && yy>=1 && yy<=n && c[xx][yy]!=c[ax[head]][ay[head]] && !b[xx][yy])
            {
                tail++;
                ax[tail]=xx;
                ay[tail]=yy;
                b[xx][yy]=1;
            }
        }   
        head++; 
    }
    for(int i=1;i<=tail;i++) ans[ax[i]][ay[i]]=tail;
}
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",a[i]+1);
        for(int j=1;j<=n;j++)
            c[i][j]=a[i][j]-'0';
    }       
    for(int i=1;i<=t;i++)
    {
        scanf("%d%d",&x,&y);
        if(!b[x][y]) bfs(x,y);
        cout<<ans[x][y]<<endl;
    }
}

看下面读入的方法scanf(“%1d”,&a[i][j])

#include<iostream>
#include<cstdio>
using namespace std;
int fx[5]={0,0,1,0,-1},fy[5]={0,1,0,-1,0},n,m,a[1001][1001],ans[1001][1001],mgx[1000001],mgy[1000001],x,y;  //数组啥的开大点,防爆(炸)嘛。
bool b[1001][1001];
void bfs(int x,int y)
{
    int h=0,t=1,tx,ty;b[x][y]=1,mgx[h]=x,mgy[h]=y;  //头标尾标啥的赋初值。mgx[h]可改成mgx[0]都一样。(说明一下,mgx和mgy是广搜用的队列。)
    while(h<t)  //do-while和while应该都可以。
    {
        for(int i=1;i<=4;i++)  //四向搜索。
        {
            tx=mgx[h]+fx[i],ty=mgy[h]+fy[i];  //tx/ty,用来判断下一步。
            if((tx>=1&&tx<=n)&&(ty>=1&&ty<=n)&&(a[tx][ty]!=a[mgx[h]][mgy[h]])&&(!b[tx][ty]))mgx[t]=tx,mgy[t]=ty,b[tx][ty]=1,t++;  //没有超界并且达到此点不等于下点的值并且没走过此点则存入队列。
        }
        h++;
    }
    for(int i=0;i<t;i++)ans[mgx[i]][mgy[i]]=t;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%1d",&a[i][j]);  //读入,也可用字符读入。
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y;  //读入起始点。
        if(!b[x][y])bfs(x,y);
        cout<<ans[x][y]<<endl;  //输出答案。
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值