DFS中的多次询问问题,并查集拓展,做标记,P1141 01迷宫

dfs是时间复杂度很高的算法,如果题目多次询问而我们每次询问都进行一次完整的dfs大概率是要超时的。所以我们要记忆化搜索,做标记,这里就要有一个好做标记的方法了:这里我介绍一种按询问次数做标记的方法。

题目描述

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

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

输入格式

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

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

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

输出格式

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

输入输出样例

输入 #1复制

2 2
01
10
1 1
2 2

输出 #1复制

4
4

说明/提示

所有格子互相可达。

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

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

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

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

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


 题目的简而言之就是问:给你一个坐标,能按题目中的要求与多少个其他坐标位置连通,给出与之连通的个数;
 这里涉及到连通性,我们考虑用并查集,要怎么用呢?
 我们这里的并查集的初始为0,之后祖先节点为m,这里的m次询问为:点y,x第一次被访问到是第m次询问
 这样我们当遇到要重复访问的点时,f[y][x]!=0,f[y][x]==m,此时我们只要去找我们之前的第m次询问的答案记录就行了;
 这里我们需要一个数组ans记录之前的答案,这里的ans就是按询问次数做标记的方法,但这个方法需要搭配上述几种或其它的方法使用。

将上述思路写成代码就是这样:


#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cstdio>
#include<iomanip>
using namespace std;
typedef long long LL;
const int N = 1e3 + 5;
string arr[N];
int vis[N][N];
int n, m,ay[]={0,1,0,-1},ax[]={1,0,-1,0},ans[100005],f[N][N], num;

void dfs(int y,int x,int I) {
	vis[y][x] = 1;

	for (int i = 0,tx,ty; i < 4; i++) {
		ty = y + ay[i];
		tx = x + ax[i];
		if (ty > 0 && ty <= n && tx > 0 && tx <= n && arr[ty][tx] != arr[y][x] && vis[ty][tx] == 0) {
			num++;
			f[ty][tx] = I;
			dfs(ty, tx,I);
		}
		else if(ty > 0 && ty <= n && tx > 0 && tx <= n && arr[ty][tx] != arr[y][x]) {
			f[y][x] = f[ty][tx];
		}
	}
	
}


int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		cin >>arr[i];
		arr[i].insert(0, " ");
	}

	

	for (int i = 1,tx,ty; i <= m; i++) {
		num = 1;
		scanf("%d%d", &ty, &tx);
		f[ty][tx] = i;
		dfs(ty, tx,i);
		num = max(num, ans[f[ty][tx]]);
		ans[i] = num;
		printf("%d\n", num);
	}

	return 0;
}

对于这道题,要有另一种做标记的方法,定义一个数组f[][],他即表示对应的点有没有被访问过,又表示该点是在第几次询问时被访问的,
 该数组初始化为0,表示没被访问过;


#include <iostream>
#include<stdio.h>
#include<string>
using namespace std;
const int MAX = 1e7;
int d[MAX], f[1010][1010];
string a[1010];
int n, m, cnt = 1;
int xx[4] = { 0,0,1,-1 };
int yy[4] = { 1,-1,0,0 };
void dfs(int x, int y)
{
	f[x][y] = cnt, d[cnt]++;
	int x1 = x, y1 = y;
	for (int i = 0; i < 4; i++)
	{
		x += xx[i];
		y += yy[i];
		/*if (x == 2 && y == 1) {
			cout << "?" << endl;
		}*/
		if (x > 0 && x <= n && y > 0 && y <= n && f[x][y] == 0 && a[x][y] != a[x1][y1])
			dfs(x, y);
		x -= xx[i];
		y -= yy[i];
	}
}
int main()
{
	int xx, yy;
	scanf("%d%d ", &n, &m);
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		a[i].insert(0, " ");
			
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		{
			if (f[i][j] == 0)
			{
				cnt++;
				dfs(i, j);
			}
		}

	for (int i = 1,t1,t2; i <= m; i++)
	{
		scanf("%d%d", &t1, &t2);
		printf("%d\n", d[f[t1][t2]]);
	}
	return 0;
}

posted @ 2023-06-15 16:59  Landnig_on_Mars  阅读(7)  评论(0编辑  收藏  举报  来源