洛谷P1162 填涂颜色(BFS广度优先搜索)

题目地址:P1162 填涂颜色 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

image

思路

基础是BFS,还不懂的同学移步 洛谷P1135 奇怪的天梯(BFS广度优先搜索基础题) - 张牧歌 - 博客园 (cnblogs.com),这里不做多赘述。
这里拿Photoshop来举例。
这里是一只嘉然,如果我不要这个白色背景,只要本体可以怎么抠图呢?
image

对PS有了解的同学可以使用魔棒工具,即选取与点击地方颜色相近的部分。将白色点出来
image

右键,点击反选,就是将白色部分排除剩下的就是整只嘉然啦。

image
效果十分好又快
image

那么回到这题,我们只需选取不在框里面的0标记,没有被标记的就是被圈起来的部分!

int markx[] = {0,1,-1,0};
int marky[] = {1,0,0,-1};
int n;
void bfs(int x,int y)
{
	pair<int, int> temp_pair = { x,y };
	q.push(temp_pair);
	while (!q.empty())
	{
		auto temp = q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			if(temp.first+markx[i]>=1&&temp.first+markx[i]<=n&&temp.second+marky[i]>=1&&temp.second+marky[i]<=n&&!a[temp.first+markx[i]][temp.second+marky[i]])
			{
				pair<int, int>t = { temp.first + markx[i],temp.second + marky[i] };
				q.push(t);
				a[t.first][t.second] = 2;
			}
		}
	}
}

输出:

for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cout << 2-a[i][j] << ' ';
		}
		cout << endl;
	}

听起来似乎很可行!但是当数据变得刁钻起来就寄了。
image
在这个数据里我们用这个方法很难找到一个起点去遍历。

已知在边缘的0是不会被1包围进去的,所以找出边缘的0去遍历就好啦!
image

AC代码

#include <iostream>
#include <queue>
using namespace std;
queue<pair<int, int>>q;
int a[32][32];
int markx[] = {0,1,-1,0};
int marky[] = {1,0,0,-1};
int n;
void bfs(int x,int y)
{
	pair<int, int> temp_pair = { x,y };
	q.push(temp_pair);
	while (!q.empty())
	{
		auto temp = q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			if(temp.first+markx[i]>=1&&temp.first+markx[i]<=n&&temp.second+marky[i]>=1&&temp.second+marky[i]<=n&&!a[temp.first+markx[i]][temp.second+marky[i]])
			{
				pair<int, int>t = { temp.first + markx[i],temp.second + marky[i] };
				q.push(t);
				a[t.first][t.second] = 2;//把外圈的0标为2,即把圈外的0全部标记
			}
		}
	}
}
int main(int argc, char* argv[])
{
	cin >> n;
	for(int i=1;i<=n;i++)
	{
		for (int j = 1; j <= n; j++)
		{
			cin >> a[i][j];
		}
	}

	for(int i=1;i<=n;i++)
	{//由于边缘的0一定是圈外的,而且与其相邻的0也是圈外的,所以可以从每个边缘开始遍历,直到撞到1
		if (!a[i][1])
			bfs(i, 1);
		if (!a[1][i])
			bfs(1, i);
		if (!a[n][i])
			bfs(n, i);
		if (!a[i][n])
			bfs(i, n);
	}

	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cout << 2-a[i][j] << ' ';//由于圈外的都被标记成2,使用2-a[i][j]即可进行翻转,使得圈外的是0,圈内的是1
		}
		cout << endl;
	}
	return 0;
}

心得:

这题居然只是普及-的难度,翻了一会儿题解靠自己脑子理解并写出来了。这个思路确实很像我P图的时候所以拿出来举例了。有被折磨到。

posted @ 2022-01-12 22:04  张牧歌  阅读(74)  评论(0编辑  收藏  举报