P1141 01迷宫(联通块/并查集)

该博客介绍了如何解决一个关于迷宫联通块的问题,其中涉及从特定格子出发可以到达的格子数量。作者首先尝试了暴力搜索的方法,但遇到超时问题,然后通过预处理和优化,逐步改进解决方案,最终使用并查集在161ms内通过了测试。博客中提到,虽然有大佬使用并查集直接处理,但作者认为两者本质相似,且并查集的一维处理方式可能更具通用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

有一个仅由数字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。

思路:读完题感觉暴力跑全图dfs能搞,全炸0分,不想debug换全图bfs70分,超时3个点。然后需要好好思索一下为什么T,转换一下题目,求的是点所在的联通块大小,也就是说联通的点值相同,那我全图预处理一下。还是T3个点,等等,我为什么要处理全图,不一定所有的块都会查询呀,那我只处理查询的点所在块,emmm,超时2个点......既然联通值相同,那我就另开数组直接存值,查询时输出。嗯,过了,161ms,还阔以。

讨论区有大佬用并查集过的,我感觉只是在联通块查询的时候用并查集处理了一下,让相同块互相并起来,感觉都差不多,实现方式嘛,绕开二维用一维处理,适用范围应该会大很多,值得学习。

蒻鶸的代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define per(i,a,b) for(int i=a;i<=b;++i)
#define ll long long


const int MAXBUF=10000;
char buf[MAXBUF],*ps=buf,*pe=buf+1;
inline void rnext()
{
    if(++ps==pe)
        pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);
}
template<class T>
inline bool in(T &ans)
{
    ans=0;
    T f=1;
    if(ps==pe) return false;
    do{
        rnext();
        if('-'==*ps) f=-1;
    }while(!isdigit(*ps)&&ps!=pe);
    if(ps==pe) return false;
    do
    {
        ans=(ans<<1)+(ans<<3)+*ps-48;
        rnext();
    }while(isdigit(*ps)&&ps!=pe);
    ans*=f;
    return true;
}//输入挂



int f[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
char mp[1005][1005];
int vis[1005][1005];
int p[1000005];
ll int n,m;
struct node{
	int x;
	int y;
};
void bfs(int u,int v,int k)
{
	int s=1;
	queue<node>q;
    node z,t1,t2;
    vis[u][v]=k;
    z.x=u;z.y=v;
    q.push(z);
    int x,y;
    while(!q.empty())
    {
    	t1=q.front(); 
		q.pop();
		if(s==n*n) break;
        per(i,0,3)
        {
            x=t1.x+f[i][0];
            y=t1.y+f[i][1];
            if(vis[x][y]==-1&&x>=1&&x<=n&&y>=1&&y<=n&&mp[x][y]-'0'!=mp[t1.x][t1.y]-'0')
            {
                vis[x][y]=k;
                s++;
                if(s==n*n) break;
                t2.x=x;t2.y=y;
                q.push(t2);
            }
		}
    }
    p[k]=s;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    per(i,1,n) scanf("%s",&mp[i][1]);
    int x,y;
    memset(vis,-1,sizeof(vis));
	int k=0;
    per(i,1,m)
    { 
        in(x);in(y);
        if(vis[x][y]==-1) bfs(x,y,k++);
        printf("%d\n",p[vis[x][y]]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值