P1162 填涂颜色 题意(bfs 广度优先搜索)

P1162 填涂颜色

题目

题目描述
由数字00组成的方阵中,有一任意形状闭合圈,闭合圈由数字11构成,围圈时只走上下左右44个方向。现要求把闭合圈内的所有空间都填写成22.例如:6 \times 66×6的方阵(n=6n=6),涂色前和涂色后的方阵如下:
填涂前

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
0 0 0 0 0 0

填涂后

0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

输入格式
每组测试数据第一行一个整数n(1 \le n \le 30)n(1≤n≤30)

接下来nn行,由00和11组成的n \times nn×n的方阵。

方阵内只有一个闭合圈,圈内至少有一个00。

输出格式
已经填好数字22的完整方阵。

输入输出样例
输入

6
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1

输出

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

说明/提示
1 \le n \le 301≤n≤30

分析

我的方法比较的讨巧。先利用dfs搜索到第一个唯一的点p,这时,我们可以发现需要填涂的点的八个方向都是被1围起来的,所以如果我们只按右和下进行搜索,那么需要填涂的点一定在p点的左下和右下,此时需要考虑三种情况:

  1. 第一个点,也就是(0,0)为1,需要填涂的点在p点的右下方;
  2. 如果p点右边为0或着p点为右边界时,需要填涂的点在p点的左下方;
  3. 否则需要填涂的点均在右下方。

找到第一个填涂点后,进行bfs,先将该点入队,入队的是该店的行列坐标,再进行该点四个方向的搜索,找到不为1或不为2的点就将该点置2并入队。队列为空时说明搜索完成。

如果还不太理解,具体的代码解释可以见我的代码注释哦~

代码


//1162
#include<iostream>
#include<queue>
using namespace std;

const int N = 35;
int n;
int map[N][N];
int ans[N][N];
int d[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
int yi[3]; //yi[0]yi[1]分别存储填涂起点行列坐标,yi[2]=1表示已找到填涂点

void dfs(int x,int y){ //搜索为1的点
	if(map[x][y] == 1){ //遇到第一个就是1的点,则表明需要填涂的点在右下角
		yi[0] = x+1;
		yi[1] = y+1;
		yi[2] = 1;
		return;
	}
	for(int i = 0;i < 2;i++){ //只需向右和下移动即可找到该点
		int xx = x + d[i][0];
		int yy = y + d[i][1];
		
		if(xx < 0 || xx >= n || yy < 0 || yy >= n) //边界判定
			continue;
		
		if(map[xx][yy] == 1){ //找到第一个为1的点,现在只有两种情况
			if(map[xx][yy+1]==0 && yy+1==n){ //需要填涂的点在左下方时
				yi[0] = xx+1;
				yi[1] = yy-1;
			}else{ //需要填涂的点在右下方时
				yi[0] = xx+1;
				yi[1] = yy+1;
			}
		
			yi[2] = 1;
			
			return;
		}
		dfs(xx,yy);
		if(yi[2] == 1){ //已找到该点,需要立即返回
			return;
		}
	}

}

void bfs(int x,int y){//从第一个填涂点开始广搜
	map[x][y] = 2; //将原始填涂点置2
	queue<int> q;
	//行列坐标入队
	q.push(x);
	q.push(y);
	
	while(!q.empty()){ 
		int xx = q.front();
		q.pop();
		int yy = q.front();
		q.pop();
		//搜索每个点上下左右的点
		for(int i = 0;i < 4;i++){
			int xxx = xx + d[i][0];
			int yyy = yy + d[i][1];
			if(map[xxx][yyy] != 1 && map[xxx][yyy] != 2){ //可以填涂
				map[xxx][yyy] = 2;	
				q.push(xxx); //将新点入队
				q.push(yyy);
			}
		}
	}	
}

int main(){
	cin>>n;
	for(int i = 0;i < n;i++){
		for(int j = 0;j < n;j++){
			cin>>map[i][j];
		}
	}
	
	dfs(0,0);
	
	bfs(yi[0],yi[1]);
	
	for(int i = 0;i < n;i++){
		for(int j = 0;j < n;j++){
			cout<<map[i][j]<<" ";
		}
		cout<<endl;
	}
	
	return 0;
} 

传送门

P1162

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值