蓝桥杯算法练习笔记(7)__深度优先搜索 DFS

7.深度优先搜索 DFS

1.迷宫问题
//迷宫问题 (旧版) 
#include<iostream>
#include<string>
using namespace std;
int n,m;
string maze[110];//存储地图,相当于二维 maze[i][j] 
bool vis[110][110];//存储是否能走/走过 
//判断是否超出边界的函数 
bool in(int x,int y){
	return 0<=x && x<n && 0<=y && y<m; 
} 

bool dfs(int x,int y){
	if(maze[x][y]=='T'){
		return true;
	}
	vis[x][y]=1;
	maze[x][y]='m';
	//往上走 (按照数组的存储下标,并未位置坐标) 
	int tx=x-1,ty=y;
	if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){
		if(dfs(tx,ty)){
			return true;
		}
	} 
	//往左走 
	tx=x,ty=y-1; 
	if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){
		if(dfs(tx,ty)){
			return true;
		}
	}
	//往下走 
	tx=x+1,ty=y;
	if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){
		if(dfs(tx,ty)){
			return true;
		}
	} 
	//往右走 
	tx=x,ty=y+1;
	if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){
		if(dfs(tx,ty)){
			return true;
		}
	} 
	//走不通的路,取消标记
	vis[x][y]=0;
	maze[x][y]='.'; 
	return false;
}
int main(){
	//输入迷宫地图 
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>maze[i];
	} 
	//寻找起始点 
	int x,y;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(maze[i][j]=='S'){
				x=i,y=j;
			}
		}
	}
	//打印地图 
	if(dfs(x,y)){
		for(int i=0;i<n;i++){
			cout<<maze[i]<<endl;
		}
	} else {
		cout<<"No!"<<endl;
	}
	
	
	return 0;
} 

/*
输入:
5 6
....S*
.***..
.*..*.
*.***.
.T....

输出: 
....m*
.***mm
.*..*m
*.***m
.Tmmmm 


*/ 
//迷宫问题(改版)
#include<iostream>
#include<string>
using namespace std;
int n,m;
string maze[110];
bool vis[110][110];

int  dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};//移动坐标 
//建议按照 逆时针 (或顺时针)方向写,方便做转头操作 

bool in(int x,int y){
	return 0<=x && x<n && 0<=y && y<m;
}

bool dfs(int x,int y){
	//找到重点 
	if(maze[x][y]=='T'){
		return true;
	}
	
	vis[x][y]=1;//走过了 
	maze[x][y]='+';//标记为+
	
	for(int i=0;i<4;i++){
		int tx=x+dir[i][0];
		int ty=y+dir[i][1];
		if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){
			if(dfs(tx,ty)){
				return true;	
			}
		}
	} 
	//走不通,取消标记
	vis[x][y]=0;
	maze[x][y]='.';
	return false; 
}


int main(){
	
	//输入迷宫地图 
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>maze[i];
	} 
	//寻找起始点 
	int x,y;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(maze[i][j]=='S'){
				x=i,y=j;
			}
		}
	}
	//打印地图 
	if(dfs(x,y)){
		for(int i=0;i<n;i++){
			cout<<maze[i]<<endl;
		}
	} else {
		cout<<"No!"<<endl;
	}
	
	
	return 0;
} 

//

//二改,个人理解版
#include<iostream>
using namespace std;

int n,m;
char maze[105][105];
bool via[105][105];

void dfs(int x,int y) {

	//cout<<"x y "<<x+1<<" "<<y+1<<endl;
	
	if(maze[x][y]=='T') {
		for(int i=0; i<n; i++) {
			for(int j=0; j<m; j++) {
				cout<<maze[i][j];
			}
			cout<<endl;
		}
		return ;
	}

	if(x<0 || x>=n || y<0 || y>=m) {
		return ;
	}

	if(!via[x][y] && maze[x][y]!='*') {

		via[x][y]=true;
		maze[x][y]='m';

		dfs(x+1,y);
		dfs(x-1,y);
		dfs(x,y-1);
		dfs(x,y+1);

		via[x][y]=false;
		maze[x][y]='.';
	}


}

int main() {

	cin>>n>>m;
	for(int i=0; i<n; i++) {
		for(int j=0; j<m; j++) {
			cin>>maze[i][j];
		}
	}
	int x,y;
	for(int i=0; i<n; i++) {
		for(int j=0; j<m; j++) {
			if(maze[i][j]=='S') {
				x=i;
				y=j;
			}
		}
	}

	dfs(x,y);

	return 0;
}
2.象棋走马
#include<iostream>
using namespace std;
/*
在下象棋中,马走‘日’,问能不能从(x,y)走到(x',y')
棋盘是一个 10 x 9 的网格,左上角(0,0),右下角(9,8)

输入:
一个键盘 
用 . 表示此位置为空,用 # 表示此位置有其他旗子
用 S 表示马起始的位置,用 T 表示最终的位置 

输出:
	Yes (并输出步数) or No 
	
例子: 
.#....#S#
..#.#.#..
..##.#..#
......##.
...T.....
...#.#...
...#.....
...###...
.........
.##...... 
*/

char s[10][10];
int dir[8][2]={{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}};
bool f;
bool vis[10][10];
int ans=1000000;

bool in(int x,int y){
	return 0<=x && x<10 && 0<=y && y<9;
}


void dfs(int x,int y,int step){
	vis[x][y]=true;
	
	if(s[x][y]=='T'){
		f=true;
		if(step<ans){
			ans=step;
		}
		return;
	}
	for(int i=0;i<8;i++){
		int tx=x+dir[i][0];
		int ty=y+dir[i][1];
		if(in(tx,ty)&&s[tx][ty]!='#'&&!vis[tx][ty]){
			dfs(tx,ty,step+1);
		}	
	}
}
 
int main(){
	
	int x,y;
	
	for(int i=0;i<10;i++){
		for(int j=0;j<9;j++){
			cin>>s[i][j]; 
		}
	}
	
	
	for(int i=0;i<10;i++){
		for(int j=0;j<9;j++){
			if(s[i][j]=='S'){
				x=i;
				y=j;
				break;
			}
		}
	}

	dfs(x,y,0);
	
	if(f){
		cout<<"Yes "<<ans<<endl; 
	}else{
		cout<<"No"<<endl;
	}
	
	return 0;
}
3.草地块问题
/*草地块问题
用 # 表示草地,用 . 表示空地
若相连的#表示为同一块草地,问共有几块
输入:
	地图
输出:
	草地块数
例子:
5 6
.#....
..#...
..#...
...##.
..#...
结果:4	 
*/
#include<iostream>
using namespace std;
char mp[105][105];
bool vis[105][105];
int n,m;
void dfs(int x,int y){
	//不符合条件 
	if(x<0 || x>=n || y<0 || y>=m || vis[x][y] || mp[x][y]=='.' ){
		return ;
	}	
	vis[x][y]=true; 
	dfs(x-1,y);
	dfs(x+1,y);
	dfs(x,y-1);
	dfs(x,y+1);
	
}
int main(){
	cin>>n>>m;
	int cnt=0;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>mp[i][j];
		}
	}
	
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(!vis[i][j] && mp[i][j]=='#'){
				cnt++;
				dfs(i,j);
				cout<<i<<j<<endl; 
			}
		}
	}
	
	cout<<cnt<<endl;
	
	return 0;
} 
4.树的子节点
题目:现要调查族谱系中每个人的直属后代(含直属后代的直属后代)一共有多少人
输入:族谱中的人数n;接下来n-1行,每行第一个数字x代表父代,第二个数字y代表子代
输出:n行,每行代表第几个人的直属后代数

示例输入:
4
1 2
1 3
2 4
示例输出:
3
1
0
0
解题思路:
与树的子代结构类似,可用递归计算
#include<iostream>
#include<vector>
using namespace std;

vector<int> son[100005];//记录
bool f[100005];//为了确定根
int ans[100005];//答案数组

int dfs(int u) {//计算这一代的人数
	int ret=0;
	//先统计包括自己的后代
	for(int i=0; i<son[u].size(); i++) {
		ret+=dfs(son[u][i]);
	}
	ans[u]=ret;
	return ret+1;//int型返回值代表这一代的人数
}


int main() {
	int x,y,n,u;
	cin>>n;
	for(int i=0; i<n-1; i++) {
		cin>>x>>y;
		son[x].push_back(y);
		f[y]=true;
	}

	for(int i=1; i<=n; i++) {
		if(!f[i]) {
			u=i;//u代表根节点
			break;
		}
	}

	dfs(u);//传入根节点
	for(int i=1; i<=n; i++) {
		cout<<ans[i]<<endl;
	}

	return 0;
}
5.马可以走到哪
#include<iostream>
using namespace std;
/*马可以走到哪里
输入棋盘的大小 nXm 输入马的起始位置 (x,y)
输出马三步以内可以到达的位置,用 # 表示 
*/
int n,m;
char mp[105][105];
bool vis[105][105];
int a[8][2]= {{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{-2,1},{2,-1},{-2,-1}};

void dfs(int x,int y,int step) {

	if(x<0 || x>=n || y<0 || y>=m ) {
		return ;
	}


	if(step >3) {
		return ;
	}

	mp[x][y]='#';

	for(int i=0; i<8; i++) {
		dfs(x+a[i][0],y+a[i][1],step+1);
		//step++ (X) ++step(X) ? 
	}

}


int main() {
	cin>>n>>m;
	for(int i=0; i<n; i++) {
		for(int j=0; j<m; j++) {
			mp[i][j]='.';
		}
	}

	int x,y;
	cin>>x>>y;
	mp[x][y]='B';
	dfs(x-1,y-1,0);

	for(int i=0; i<n; i++) {
		for(int j=0; j<m; j++) {
			cout<<mp[i][j];
		}
		cout<<endl;
	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值