dfs之填涂颜色问题

本文详细解析了洛谷平台上的几道典型涂色问题,包括拯救oibh总部、填涂颜色和CF445ADZYLovesChessboard。通过DFS深度优先搜索算法,探讨如何遍历地图并进行有效的染色。文章强调了边界检查、避免重复染色以及巧妙的递归逻辑在解题中的关键作用,并提供了清晰的代码实现。
摘要由CSDN通过智能技术生成

题目1:

P1506 拯救oibh总部 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目很好,我分析的尽量充分一点

#include<iostream>
#include<cstdio>
using namespace std;   
char ch;   
int x,y,ans,map[550][550],dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1};//dx,dy是上下左右四个方向(把0空了过去) 
void dfs(int m,int n)  
{ 
    if(m<0||n<0||m>x+1||n>y+1||map[m][n])  //如果越界或有障碍就回溯 ---------1
        return;  
    map[m][n]=2;   
    for(int i=1;i<=4;i++)  //上下左右搜索 
        dfs(m+dx[i],n+dy[i]);------------------------------------2
}  
int main()
{
    scanf("%d%d",&x,&y);
    for(int i=1;i<=x;i++)  //习惯处理成数字地图 
        for(int j=1;j<=y;j++)
        {
            cin>>ch;  
            if(ch=='0')  
                map[i][j]=0; 
            else map[i][j]=1;--------------------------------3
        }
    dfs(0,0);   //洪水开始泛滥 --------------------------------4
    for(int i=1;i<=x;i++)  //寻找没有被洪水袭击的点即未被染色的点 
        for(int j=1;j<=y;j++)
            if(!map[i][j])-------------------------------------5
                ans++;   
    printf("%d",ans);
    return 0;  
}

理解点1:为什么说是大于x+1和大于y+1这是为了防止有遗漏

2:是遍历四个方向的常规写法

3:这个地方是首先遍历地图将想要的0赋值为0,将*赋值为1,这样便于理解

4:当这个值还是0不是2的时候说明它被*号所包围了,因此就是你要的值

理解,为啥被包围的0遍历不到呢??

答:首先看理解1出、处的条件,当值为1即碰见*的时候是不向四个方向遍历的(return语句的作用),因此当四个方向都是*号的时候那么中间的就永远遍历不到了呀。

题目2:

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

仿照第一题的写法,真的是果然开朗呀。洛谷一遍过了。

#include<iostream>
#include<cstdio>

using namespace std;
int n;
int a[50][50];
int map[50][50];
int dirx[5] = {0,-1,1,0,0 };
int diry[5] = {0,0,0,-1,1 };

void dfs(int x, int y)
{
	if (x<0||y<0||x > n + 1 || y > n + 1 || map[x][y])
		return;
	map[x][y] = 3;//注意这条语句千万不能放到最前面,要先判断出界与否,在执行下面的语句
	for (int i = 1; i <=4; i++)
		dfs(x + dirx[i], y + diry[i]);
}

int main()
{
	cin >> n;
	for(int i=1;i<=n;i++)
		for (int j =1; j <=n; j++)
		{
			cin >> a[i][j];
			if (a[i][j] == 0)
				map[i][j] = 0;
			else
				map[i][j] = 1;
		}
	dfs(0, 0);
	for (int i = 1; i <=n; i++)
		for (int j = 1; j <=n; j++)
		{
			if (map[i][j] == 0)//主要是这里不太一样,当你被包围住那就还是0,那就按照要求赋值2
				a[i][j] = 2;
			if (map[i][j] == 3)
				a[i][j] = 0;//把你赋值过的再赋值回去,这里是点睛之笔
		}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
			cout << a[i][j] << " ";
		printf("\n");
	}
	return 0;

}

这两篇题目应该是涂色问题的典型了。好好理解。

题目三:

CF445A DZY Loves Chessboard - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这道题我的收获的最大值之处在于对不重复标记的解决办法。

#include<iostream>

using namespace std;

int m, n;
int dirx[4] = { 1,-1,0,0 };
int diry[4] = { 0,0,1,-1 };
char map[100][100];

void dfs(char f, int x, int y)
{
	if (x<0 || y<0 || x>n + 1 || y>m + 1 || map[x][y])
		return;
	map[x][y] = f;------------------------------------------------1
	for (int i = 0; i < 4; i++)
		dfs(f=='W'?'B':'W', x + dirx[i], y + diry[i]);------------2
}

int main()
{
	cin >> n >> m;
	for(int i=1;i<=n;i++)
		for (int j = 1; j <= m; j++)
		{
			cin >> map[i][j];
			if (map[i][j] =='.')
				map[i][j] = 0;
			else
				map[i][j] = 1;
		}
	dfs('B',0, 0);------------------------------------------------3
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cout << map[i][j];
		}
		printf("\n");
	}
	return 0;
}

可以发现,其他代码和模板几乎没有任何的区别,区别就在于三个理解点

理解点1:这个地方是直接赋值字符

2.最最巧妙之处了,当f==w时,f就是w,当f==B时,f反而等于w,这就是a>b?a:b;语句的用法

巧妙之处避免相邻的字符是一样的。

3.dfs函数多加一个变量而已。

此外,题解里面的也很好,符合dfs的函数模板

#include<cstdio>
#include<iostream>
using namespace std;

int n, m;
char map[105][105]; //棋盘 
int dx[4] = { 0, 1, 0, -1 };//斜度偏移数组,上下左右 
int dy[4] = { 1, 0, -1, 0 };

void dfs(char f, int x, int y)//F与上一次搜索的点的棋子不同, X是它的纵坐标,y是横坐标 
{
	map[x][y] = f;//保存 
	for (int i = 0; i < 4; i++)//扫描上下左右 
	{
		int x_new = x + dx[i], y_new = y + dy[i];//新位置 
		if (map[x_new][y_new] == '.' && x_new >= 1 && x_new <= n && y_new >= 1 && y_new <= m)//判断是否非法 
		{
			dfs(f == 'W' ? 'B' : 'W', x_new, y_new);//搜索下一个 
		}
	}
}

int main()
{
	cin >> n >> m;//输入 
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			cin >> map[i][j];//输入 
		}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			if (map[i][j] == '.') dfs('B', i, j);//如果是好格,直接深搜 
		}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cout << map[i][j];//输出 
		}
		puts("");//换行 
	}

	return 0;
}

        

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值