ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷 P1141 01迷宫

2021-11-12 22:05:08  阅读:204  来源: 互联网

标签:01 洛谷 tx ty int top father chart P1141


洛谷 P1141 01迷宫

BFS或者并查集

题目描述

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

说明/提示

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

对于输入一组,bfs一遍,代码我放在下面:(只能过70%)

#include <iostream>
#include <queue>
using namespace std;
const int N = 1005;

int direct[4][2] = {{0,1},{-1,0},{0,-1},{1,0}};//方向
bool flag[N][N]={false};
char chart[N][N];

typedef struct{
	int x, y;
}Node;
int n, m;

void init() {
	for ( int i = 1; i <= n; ++i ) {
		for ( int j  = 1; j <= n; ++j )
			flag[i][j] = false;
	}
}

void bfs(Node k)
{
	int ans = 1;
	flag[k.x][k.y] = true;
	queue<Node> q;
	q.push(k);
	while ( !q.empty() ) {
		Node top = q.front();
		q.pop();
	
		for ( int i = 0; i < 4; ++i ) {
			int tx = top.x + direct[i][0];
			int ty = top.y + direct[i][1];
			//满足条件
			if ( tx >= 1 && tx <= n && ty >= 1 && ty <= n
				&& !flag[tx][ty] )
			{
				if ( chart[top.x][top.y] == '0' && chart[tx][ty] == '1'
				  || chart[top.x][top.y] == '1' && chart[tx][ty] == '0'
				)
				{
					Node temp = {tx,ty};
					q.push(temp);
					flag[tx][ty] = true;
					ans++;
				}
			}
		}
	}
	cout << ans <<endl;
}

int main()
{
	cin >> n >> m;
	
	for ( int i = 1; i <= n; ++i ) {
		for ( int j = 1; j <= n; ++j ) {
			cin >> chart[i][j];
		}
	}
	while (m--) {
		int x, y;
		cin >> x >> y;
		Node now = {x,y};
		bfs(now);
		init();
	}
	
	return 0;
}

其实没有必要重复bfs,是吧,因为从一个点只要能到的那一片,这一片的这些点的结果都是一样的。

就是一片连通的点就是一个集合(很容易想到并查集,我这里先不说并查集,用这样一个思想来做一遍)

看下面的帮助理解:

假如样例是这样的:

4 4
0101
1000
1000
1000
1 1
4 4
2 2
1 3
    
(1,1)(4,4)这个点可以到达的方格(用#和@标记出来了)
####
##00
1000
100@

(1,1)是我们输入的第1个点,所以#的方格的父亲就标记为1
(1,1)最开始没有父亲,bfs一遍,把它能到的点,都给标记上父亲1
father[1][1] = father[1][2] = father[1][3] =
father[1][4] = father[2][1] = father[2][2] = 1;
在bfs最后,dis[1] = 6(ans);
    
(4,4)是我们输入的第2个点,所以@的方格的父亲就标记为2
father[4][4] = 2;
在bfs最后,dis[2]= 1(ans);

(2,2)发现他有父亲,直接输出父亲的结果,dis[father[2][2]] = dis[1] = 6;
(1,3)发现他有父亲,直接输出父亲的结果,dis[father[1][3]] = dis[1] = 6;

这样,当我们输入一个集合里面的点来查询的时候,我们只需要
看看有没有父亲,如果有,就直接输出父亲的结果;没有就bfs。
这样就节省了很多时间。

要点:(每个集合我们定义一个父亲,父亲和所有孩子的结果是一样的)

  • father[i] [j]数组的值表示(i, j)这个点的父亲。什么意思呢?father[2] [2] = 1,意思就是(2,2)这个点他的父亲是我们输入的第一个点。

  • father[i] [j] = k, 表示(i,j)这个点的结果跟我们输入的第k个点的结果是一样的

  • dis[i] 数组表示 我们输入的 第 i 个点可以到达的方格数

#include <iostream>
#include <queue>
using namespace std;
const int N = 1005;
const int M = 1e5+5;

int direct[4][2] = {{0,1},{-1,0},{0,-1},{1,0}};//方向
int father[N][N]={0}, dis[M];
bool flag[N][N]={false}; //访问标记
char chart[N][N]; //存二维字符数组

typedef struct{
	int x, y;
}Node;//定义点
int n, m;

//now_m表示当前集合的  父亲点
void bfs(Node k, int now_m)
{
	father[k.x][k.y] = now_m;
	
	int ans = 1;
	flag[k.x][k.y] = true;
	queue<Node> q;
	q.push(k);
	while ( !q.empty() ) {
		Node top = q.front();
		q.pop();
	
		for ( int i = 0; i < 4; ++i ) {
			int tx = top.x + direct[i][0];
			int ty = top.y + direct[i][1];
			//满足条件
			if ( tx >= 1 && tx <= n && ty >= 1 && ty <= n
				&& !flag[tx][ty] )
			{
				if ( chart[top.x][top.y] == '0' && chart[tx][ty] == '1'
				  || chart[top.x][top.y] == '1' && chart[tx][ty] == '0'
				)
				{
					Node temp = {tx,ty};
					q.push(temp);
					flag[tx][ty] = true;
					father[tx][ty] = now_m;//当前点的父亲标记为now_m
					ans++;
				}
			}
		}
	}
    //当前集合父亲点能够到达的方格数
	dis[now_m] = ans;
}

int main()
{
	cin >> n >> m;
	
	for ( int i = 1; i <= n; ++i ) {
		for ( int j = 1; j <= n; ++j ) {
			cin >> chart[i][j];
		}
	}
	for ( int i = 1; i <= m; ++i ) {
		int x, y;
		cin >> x >> y;
		Node node = {x,y};
        //没父亲
		if ( father[x][y] == 0 ) {
			bfs(node,i);
		}
        //有父亲,结果就等于父亲的结果
		else {
			dis[i] = dis[father[x][y]];//结果就是他的父亲的结果
		}
	}
	for ( int i = 1; i <= m; ++i ) {
		cout << dis[i] << '\n';
	}
		
	return 0;
}

标签:01,洛谷,tx,ty,int,top,father,chart,P1141
来源: https://blog.csdn.net/okok__TXF/article/details/121296857

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有