洛谷P1683-入门 利用 dfs(递推)实现

ps:我没有看过其他题解,只跟着一位 up (后面给了up的链接)从0开始入门dfs,这个思路我认为肯定有人已经发过了,但我还是希望分享一下做题时的思考。

误打误撞学 dfs 时用 递推关系式做出来了

题目链接:P1683 入门 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)


题目描述如下:

入门

题目描述

不是任何人都可以进入桃花岛的,黄药师最讨厌像郭靖一样呆头呆脑的人。所以,他在桃花岛的唯一入口处修了一条小路,这条小路全部用正方形瓷砖铺设而成。有的瓷砖可以踩,我们认为是安全的,而有的瓷砖一踩上去就会有喷出要命的毒气,那你就死翘翘了,我们认为是不安全的。你只能从一块安全的瓷砖上走到与他相邻的四块瓷砖中的任何一个上,但它也必须是安全的才行。

由于你是黄蓉的朋友,她事先告诉你哪些砖是安全的、哪些砖是不安全的,并且她会指引你飞到第一块砖上(第一块砖可能在任意安全位置),现在她告诉你进入桃花岛的秘密就是:如果你能走过最多的瓷砖并且没有死,那么桃花岛的大门就会自动打开了,你就可以从当前位置直接飞进大门了。

注意:瓷砖可以重复走过,但不能重复计数。

输入格式

第一行两个正整数 W W W H H H,分别表示小路的宽度和长度。

以下 H H H 行为一个 H × W H\times W H×W 的字符矩阵。每一个字符代表一块瓷砖。其中,. 代表安全的砖,# 代表不安全的砖,@ 代表第一块砖。

输出格式

输出一行,只包括一个数,即你从第一块砖开始所能安全走过的最多的砖块个数(包括第一块砖)。

样例 #1

样例输入 #1

11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........

样例输出 #1

59

提示

数据规模与约定

对于全部的测试点,保证 1 ≤ W , H ≤ 20 1 \leq W,H\le 20 1W,H20


看的b站up讲了这道题自己先试着做了一下,运气好,A了。

视频链接:DFS正确入门方式 | DFS + 递归与递推习题课(下) | 一节课教你爆搜!_哔哩哔哩_bilibili

这个up讲的很细致!

up之前讲的课对于 dfs 都是用的 void 型,这就使得需要额外创建变量来存储我们需要得到的结果。

但是对于这道题,我认为可以将 dfs 函数定义为 int 型。理由如下:

分析

我在标题处提到了树的思想——初始点是根节点(记为 (x,y) ),它有四个子节点(上,下,左,右)。我们只需要计算这个根节点连了多少个子节点即可完成这道题。

所以递推关系式显而易见了:
a n s = d f s ( x − 1 , y ) + d f s ( x + 1 , y ) + d f s ( x , y − 1 ) + d f s ( x , y + 1 ) ans = dfs(x-1,y)+dfs(x+1,y)+dfs(x,y-1)+dfs(x,y+1) ans=dfs(x1,y)+dfs(x+1,y)+dfs(x,y1)+dfs(x,y+1)

加上限定条件:

int dfs(int x,int y)
{
	st[x][y]=1; // 判断该点是否走过,如果多个子节点可以走到该点,那么随便让一个走一次即可
	int sum=1; 
	for(int i=0;i<4;++i)
	{
		int xx=x+dx[i],yy=y+dy[i]; // dx[i]表示横坐标变换,dy[i]表示纵坐标变换 i=0,1,2,3 表示 上下左右(顺序无所谓)
		if(xx<1 || xx>H || yy<1 || yy>W) continue;
		
		if(maze[xx][yy]==1 && !st[xx][yy]){ //maze[x][y]表示该点是可走 or 不可走 or 初始点
			sum+=dfs(xx,yy);
		}
	}
	return sum;
}

完整代码如下(个人感觉挺好理解的):

#include<iostream>
using namespace std;

const int N=21;
int maze[N][N]; // 1 available ; 2 poison ; 3 initial
int W,H;
char c;
bool st[N][N];
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; // 0上 1下 2左 3右 

int dfs(int x,int y)
{
	st[x][y]=1;
	int sum=1; 
	for(int i=0;i<4;++i)
	{
		int xx=x+dx[i],yy=y+dy[i];
		if(xx<1 || xx>H || yy<1 || yy>W) continue;
		
		if(maze[xx][yy]==1 && !st[xx][yy]){
			sum+=dfs(xx,yy);
		}
	}
	return sum;
}
int main()
{
	cin>>W>>H;
	int x,y;
	for(int i=1;i<=H;++i)
	{
		for(int j=1;j<=W;++j)
		{
			cin>>c;
			switch(c)
			{
				case '.': maze[i][j]=1;
						  break;
				case '#': maze[i][j]=2;
						  break;
				case '@': maze[i][j]=3;
						  break;
			}
			if(c=='@'){
				x=i;y=j;
			}
		}
	}
	cout<<dfs(x,y);
	return 0;
}

ps:虽说上述方法很好理解,但是这个题还是用来训练搜索的(

​ 所以最后还是得用 dfs 和 bfs 再做一次(哭

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值