日常做人系列:普及村之搜索

1.联通块

01迷宫

https://www.luogu.org/problemnew/show/P1141
暴力解法————咋呼
求联通块————perfect

#include<bits/stdc++.h>
using namespace std;

const int MAX = 1000 + 99;
int n,m;
int flag[MAX][MAX];//flag保存每个点所在的联通图的编号(可以顺便表示出当前点访问过没有) 
int arr[MAX][MAX];//各点的1/0 
int ans[MAX*MAX];//保存每个联通图中点的个数(因为是联通的,所以这里面每个点都可以到达) 
string tmp;
int cnt;//当前是在第几个联通图中 

struct node{
	int x,y;
};
queue <node> q;

int dx[5] = {0,0,-1,0,1};
int dy[5] = {0,-1,0,1,0};

int main() {
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++) {
		cin >> tmp;
		for(int j = 0; j < n; j++) {
			arr[i][j+1] = tmp[j] - '0';
//			printf("%d ",arr[i][j+1]);
		}
//		printf("\n");
	}
	node e1,e2;
	int nx,ny,x,y;
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			if(!flag[i][j]) {//当前点不在已知的联通图中 
				cnt++;
				ans[cnt] = 1;//初始化 
				flag[i][j] = cnt;
				e1.x = i, e1.y = j;
				q.push(e1);
				while(!q.empty() ) {
					e2 = q.front();
					q.pop();
					x = e2.x, y = e2.y ;
					for(int k = 1; k <= 4; k++) {
						nx = x + dx[k], ny = y + dy[k];
						if(nx<=n && nx>=1 && ny<=n && ny>=1 && arr[nx][ny] != arr[x][y] && !flag[nx][ny])
						{
							ans[cnt]++;
							flag[nx][ny] = cnt;
							
							e1.x = nx, e1.y = ny;
							q.push(e1);
						}
					}
				}

			}
		}
	}
	int tmp2, tmp3;
	for(int i = 1; i <= m; i++) {
		scanf("%d%d",&tmp2,&tmp3);
		printf("%d\n",ans[ flag[tmp2][tmp3] ]);
	}
}

2.涂色法(最近太依赖BFS了,都忘了DFS的好处了)

  1. https://www.luogu.org/problemnew/show/P1506
  2. https://www.luogu.org/problemnew/show/P1162
    ps: 两种做法
  3. 拯救oibh总部:标准涂色
/*
涂色法
*/ 
#include<bits/stdc++.h>
using namespace std;

string s[500+9];
int arr[500+9][500+9];
int x,y,nx,ny,ans;
int dx[] = {0, 0, -1, 0, 1};
int dy[] = {0, -1, 0, 1, 0};

void dfs(int a, int b) {
		if(a<0 || a>x+1 || b<0 || b>y+1 || arr[a][b]) return ;//找既是陆地,有没涂过色的 
		arr[a][b] = 1;//1表示凃过色 
		for(int k = 1; k <= 4; k++) {
			dfs(a+dx[k],b+dy[k]);
		}
}	

int main() {
	scanf("%d%d",&x,&y);
	for(int i = 1; i <= x; i++) {
		cin >> s[i] ;
		for(int j = 1; j <= y; j++) {
			if(s[i][j-1] == '0') arr[i][j] = 0;
			else arr[i][j] = 2;//2表示有障碍 /且 2 不是陆地 
		}
	}
	dfs(0,0);//虚拟外面还有 一层"总部",这样就可以不用麻烦去找真实总部外面没有墙的地方在哪
	//直接就可以涂色 
	for(int i = 1; i <= x; i++) {
		for(int j = 1; j <= y; j++) {
			if(arr[i][j] == 0) // 没凃过色的 陆地 就是没有被淹没的点 
			{
				ans++;
			}
			 
		}
	}
	printf("%d",ans);
}
  1. 填涂颜色(另一种想法,本质上是一样的,就是可以换一种理解方式)
#include<bits/stdc++.h>
using namespace std;
const int MAX = 30 + 99;

int n;
int flag[MAX][MAX];
//思路: 从边界找“0” 并向外拓展,能够拓展得到的“0” 都不在圈内 

int dx[5] = {0,0,-1,0,1};
int dy[5] = {0,-1,0,1,0};

void dfs(int x, int y) {
	if(x<0 || x>n+1 || y<0 || y>n+1 || flag[x][y] == 1 || flag[x][y] == 2 )return ; 
	                                    //先判断:超界或者遇到障碍或已经凃过色 都要回溯
	flag[x][y] = 2;
	for(int k = 1; k <= 4; k++) dfs(x+dx[k], y+dy[k]);
} 

int main() {
	scanf("%d",&n);
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			scanf("%d",&flag[i][j]);//1 表示障碍 
			//这里的意图是只用一个数组表示全部 ,此时,我用的 2 表示涂过色 
		// 而 如果另加一个数组也许,用这个数组表示为“0”点的性质(即在圈内还是圈外)即可 
		}
	}
	//开始涂色 
	dfs(0,0);//依然是虚拟最最外层
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			if(flag[i][j] == 0) printf("2 ");
			else if(flag[i][j] == 2) printf("0 ");//涂过色的都在圈外面
			else printf("1 "); 
		}
		printf("\n");
	} 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值