1. 蓝桥杯国赛训练营--深度优先搜索--迷宫游戏

(1)题目:

思路:

代码:

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
	/*
测试数据1
3 4
S**.
....
***T

测试数据2
5 6
....S*
.***..
.*..*.
*.***.
.T....
	 * */
	static char[][] g;
	static int n;//行
	static int m;//列
	static int[][] v;//访问数组,避免重复访问
	static ArrayList<Character> ans = new ArrayList<Character>();//存放路径
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		g = new char[n][];
		v = new int[n][m];
		for(int i=0;i<n;i++) {
			g[i] = sc.next().toCharArray();
		}
		//先找到起点
		int x=0,y=0;
		boolean flag=false;
		for(int i=0;i<n&&!flag;i++) {
			for(int j=0;j<m&&!flag;j++) {
				if(g[i][j]=='S') {
					x=i;
					y=j;
					flag=true;
					break;
				}
			}
		}
		v[x][y]=1;//已访问
		dfs(x,y);//从第一个位置开始遍历
	}
	private static void dfs(int x, int y) {
		v[x][y]=1;//标记已访问
		if(g[x][y]=='T') {//走到终点,退出
			System.out.println(ans);
			System.exit(0);
		}
		//下一个位置合法,并且是.或T,且未被访问。则将该操作加入路径集合ans
		if(x+1>=0 && x+1<n && (g[x+1][y]=='.' || g[x+1][y]=='T') && v[x+1][y]!=1) {
			ans.add('D');//上
			int index = ans.size()-1;
			dfs(x+1,y);
			ans.remove(index);//回溯
		}
		if(x-1>=0 && x-1<n && (g[x-1][y]=='.' || g[x-1][y]=='T') && v[x-1][y]!=1) {
			ans.add('U');//上
			int index = ans.size()-1;
			dfs(x-1,y);
			ans.remove(index);//回溯
		}
		if(y+1>=0 && y+1<m && (g[x][y+1]=='.' || g[x][y+1]=='T') && v[x][y+1]!=1) {
			ans.add('R');//上
			int index = ans.size()-1;
			dfs(x,y+1);
			ans.remove(index);//回溯
		} 
		if(y-1>=0 && y-1<m && (g[x][y-1]=='.' || g[x][y-1]=='T') && v[x][y-1]!=1) {
			ans.add('L');//上
			int index = ans.size()-1;
			dfs(x,y-1);
			ans.remove(index);//回溯
		}
		v[x][y]=0;//没有找到出口,回溯
	}
}
	

(2)题目:最优剪枝问题

针对问题1,找出从起点S到终点T的最少步数

代码:

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
	/*
	 * 最优性剪枝(每次遍历将 多于 当前最优解步数的 直接剪掉)
	 * 问题:找出起点S到终点T的最少步数
测试数据1
3 4
S**.
....
***T

测试数据2
5 6
....S*
.***..
.*..*.
*.***.
.T....
	 * */
	static char[][] g;
	static int n;//行
	static int m;//列
	static int[][] v;//访问数组,避免重复访问
	static int[][] arr = {{-1,0},{1,0},{0,1},{0,-1}};//方向的变化数组
	static int ans=9999999;//记录当前最少步数
	public static void main(String[] args){
		//1.输出相关值
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		g = new char[n][];
		v = new int[n][m];
		for(int i=0;i<n;i++) {
			g[i] = sc.next().toCharArray();
		}
		//2.先找到起点
		int x=0,y=0;
		boolean flag=false;
		for(int i=0;i<n&&!flag;i++) {
			for(int j=0;j<m&&!flag;j++) {
				if(g[i][j]=='S') {
					x=i;
					y=j;
					flag=true;
					break;
				}
			}
		}//for
		//3.深度优先遍历
		dfs(x,y,0);//当前起点(x,y) ,当前已走步数0
		System.out.println(ans);
	}
	
	//深度优先遍历
	private static void dfs(int x, int y, int step) {
		
		//1.最优剪枝。当前已走的步数>当前最优解步数
		if(step>=ans) return;
		//2.已到达终点,记录最优解
		if(g[x][y]=='T') {
			ans = step;//在2中已把步数大于ans的剪枝
			return;
		}
		//3.设置当前位置为已访问(完成前面2步操作后,再设置访问标志)
				v[x][y]=1;
				
		//4.针对四个方向,进行深度优先遍历
		for(int i=0;i<4;i++) {
			int newx = x+arr[i][0];
			int newy = y+arr[i][1];
			//该位置合法,并且未被访问
			if(newx>=0 && newx<n && newy>=0 && newy<m && g[newx][newy]!='*' &&v[newx][newy]!=1 ) {
				dfs(newx,newy,step+1);
			}
		}
		//5.没有找到最优解,回溯
		v[x][y] = 0;
	}
	
}
	

(3)题目:找出起点s到终点e的所有方案数

代码:

import java.util.Scanner;

public class Main {
	/*
	 * 思路:
测试数据
5 5
s####
.####
.####
.####
....e
正常输出:2
	 * */
	static int n;//行
	static int m;//列
	static int cnt=0;//记录总的方案数
	static boolean[][] v;
	static int[][] t = {{1,0},{-1,0},{0,1},{0,-1}};
	public static void main(String[] args){
		//1.输出相关值
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();//n行
		int m = sc.nextInt();//m列
		char[][] g = new char[n][];
		v = new boolean[n][m];
		
		for(int i=0;i<n;i++) {
			g[i] = sc.next().toCharArray();
		}//for
		//2.寻找起点
		int x=0,y=0;
		for(int i=0;i<n;i++) {
			for(int j=0;j<m;j++) {
				if(g[i][j]=='s') {
					x=i;
					y=j;
					break;
				}
			}
		}
		//3.深度优先遍历
		dfs(x,y,g);//从起点开始进行遍历
		//4.输出答案
		System.out.println(cnt);
		
	}
	private static void dfs(int x, int y, char[][] g) {
		if(x<0 || x>=g.length || y<0 || y>=g[0].length || g[x][y]=='#' || v[x][y]) {//下标越界 或 墙壁 或已访问
			return;
		}
		if(g[x][y]=='e') {//到达终点,方案数+1
			cnt++;
			return;
		}
		
		v[x][y]=true;
		for(int i=0;i<4;i++) {//访问下一个位置
			int xx = x+t[i][0];
			int yy = y+t[i][1];
			dfs(xx,yy,g);
		}//for
		v[x][y]=false;//回溯
		
	}
	
}
	

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值