DFS -- DFS模拟赛补题报告

题目均有可达鸭编程提供(难度仅为本人观点)

本文有点长,注意休息

一、目录

1.山峰和山谷(难度:中)

2.沼泽问题(难度:易)

3.蚂蚁移动问题(难度:难)

二、讲解题目及AC代码

1.山峰和山谷(难度:中)

时间限制:1秒        内存限制:128M

题目描述

FGD小朋友特别喜欢爬山,在爬山的时候他就在研究山峰和山谷。
为了能够对旅程有一个安排,他想知道山峰和山谷的数量。
给定一个地图,为FGD想要旅行的区域,地图被分为 n×n 的网格,每个格子 (i,j) 的高度 w(i,j) 是给定的。
若两个格子有公共顶点,那么它们就是相邻的格子,如与 (i,j) 相邻的格子有(i−1,j−1),(i−1,j),(i−1,j+1),(i,j−1),(i,j+1),(i+1,j−1),(i+1,j),(i+1,j+1)。
你的任务是,对于给定的地图,求出山峰和山谷的数量,如果所有格子都有相同的高度,那么整个地图即是山峰,又是山谷。

输入描述

第一行包含一个正整数 n,表示地图的大小(1<=n<=1000)。
接下来一个 n×n 的矩阵,表示地图上每个格子的高度 w(0<=w<=1000000000)。

输出描述

共一行,包含两个整数,表示山峰和山谷的数量。

样例

输入

5
8 8 8 7 7
7 7 8 8 7
7 7 7 7 7
7 8 8 7 8
7 8 8 8 8

输出

2 1

提示

山峰定义为:一个连通块,对于每一个属于此连通块的点,有:这个点周围所有与它八连通的点值都比这个点的值要小
山谷定义为:一个连通块,对于每一个属于此连通块的点,有:这个点周围所有与它八连通的点值都比这个点的值要大。

此时有很多老六的地方:

1.我标黄色的山峰和山谷的定义,

2.他是与他的八连通图,而不是周围的图(也就是说平峰平谷的才算)。

解题思路:

        因为他要算山峰和山谷,一个就是想到用DFS分成两个DFS来算,但是他会时间超限(时间大约为1e6(10的6次方)个),所以说怎么解呢?既然在DFS干不成的事,那就在DFS外面干。

题解分析:

        首先呢还是正常的输入和循环遍历输入这个图,然后再遍历这整个图定义一个山峰和山谷,假设这一块儿既是山峰又是山谷,然后DFS,但是DFS只能判他不是所以就要定义一个山峰和山谷的一个变量来判断它是山峰还是山谷,通过山峰和山谷的变化来判断这是山峰的一部分,还是不是山峰或山谷。在DFS时还是比较正常的DFS,但是要判断它周围是比它高的。如果周围比他高,让他断然不是山峰;如果周围有比他矮的,那他断然不是山谷。

综上所述,AC代码如下:

#include<iostream>
using namespace std;
int n;
char dt[15][15]; //地图 
int dx[]={-1,0,0,1},dy[]={0,-1,0,1};  //方向数组 
int cnt;  //记录路线总数 
bool vis[15][15]; 
void dfs(int x,int y){
	vis[x][y]=1;  //vis先标记 
	if (x==n&&y==n){ //终点判断 
		cnt++;
		vis[x][y]=0;
		return ;
	}
	for (int i=0;i<4;i++){
		int nx=x+dx[i],ny=y+dy[i];
		if (nx>=1&&ny<=n&&nx<=n&&ny>=1){
			if (vis[nx][ny]==0&&dt[nx][ny]=='0'){
				vis[nx][ny]=1;
				dfs(nx,ny);
				vis[nx][ny]=0; //回溯 
			}
		}
	}
}
int main(){
	cin>>n;
	for (int i=1;i<=n;i++){
		for (int j=1;j<=n;j++){
			cin>>dt[i][j];
		}
	}
	dfs(1,1); //从头开始 
	cout<<cnt;
	return 0; 
} 

2.沼泽问题(难度:易)

时间限制:1秒        内存限制:128M

题目描述

达达要穿过一片N*N(2<=N<10)的沼泽地,入口和出口分别在左上角和右下角。沼泽地中的路分别放0和1,0表示可以走的道路,1表示不能走的泥沼,入口和出口处肯定是0。沼泽地行走的规则如下所示:即从某点开始,有四个方向可走,前进方格中数字为0时表示可通过,为1时表示不可通过,要另找路径。 找出所有从入口(左上角)到出口(右下角)的路径(不能重复),输出路径总数,如果无法到达,则输出0。

输入描述

第一行输入一个整数N,代表沼泽的的边长。

第2-N+1行输入每行输入N个整数(0 1),用来描述沼泽地地形

输出描述

一个整数,代表所有不重复的路径数量

样例

输入

3
000
010
000

输出

2

你只要学过DFS&&能读懂题就非常的简单,所以该题作者这并不打算为读者准备题解思路。

题解分析:

        这个题实际上就是考的著名的迷宫问题。就是求从左上角走到右下角有多少个路径可以选择,并且此题题解中肯定会掺杂一个东西,就是回溯(回溯时一定要注意,要把该回溯的都回溯了)。当然啦,这个题还有一个老6点,注意看输入描述,数字与数字之间没有空格。所以不能用int来存储,应该用char类型来存储。

所以说直接上AC代码:

#include<iostream>
using namespace std;
int n,sf,sg;//输入的数据n,Sf和sg在这里是为了方便在DFS时不传参。 
int dx[]={-1,-1,-1,0,0,1,1,1},dy[]={-1,0,1,-1,1,-1,0,1};//方向数组 
int a[1005][1005]; //为了储存地图,因为有空格,所以不用定义为char类型的。 
bool vis[1005][1005]; //标记数组为了防止DFS死循环,防止回搜 
void dfs(int x,int y){
	vis[x][y]=1;
	for (int i=0;i<8;i++){
		int nx=x+dx[i],ny=y+dy[i];
		if (nx>=1&&nx<=n&&ny>=1&&ny<=n){
			if (a[x][y]<a[nx][ny]){  //如果这个点比他的下一个点要小那他一定不是山峰
				sf=0;
			}
			if (a[x][y]>a[nx][ny]){  //如果这个点比他的下一个点要小那他一定不是山谷 
				sg=0; 
			}
			if (a[nx][ny]==a[x][y]&&vis[nx][ny]==0){
				dfs(nx,ny);
			}
		}
	}
}
int main(){
	cin>>n;
	for (int i=1;i<=n;i++){
		for (int j=1;j<=n;j++){
			cin>>a[i][j];      //循环遍历输入此地图 
		}
	} 
	int cntf=0,cntg=0;//定义两个计数器,一个记录山峰,一个记录山谷。
	for(int i=1;i<=n;i++){
		for (int j=1;j<=n;j++){  //循环遍历这个地图并以i,j这个点为起点进行DFS。
			sf=1,sg=1;      //一开始认为他既是山峰又是山谷
			if (vis[i][j]==0){
				dfs(i,j);
				if (sg==0&&sf==1){  //如果说它是山峰,那么山峰++
					cntf++;
				}
				else if (sg==1&&sf==0){  //如果说它是山谷,那么山谷++
					cntg++;
				}
				else if (sg==1&&sf==1){  //如果说它既是山峰又是山谷,那么山谷++山峰也++。 
					cntf++;
					cntg++;
				}
			} 
		}
	} 
	cout<<cntf<<" "<<cntg; 
	return 0;
} 

第三题先发VIP,在周五晚9:00发免费版

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值