I’m stuck!(CCF201312-5)解析(java实现)

在这里插入图片描述

代码

package test_201312;

import java.util.Scanner;

/*
 * 201312-5
试题名称:	I’m stuck!
时间限制:	1.0s
内存限制:	256.0MB
问题描述:	
问题描述
  给定一个R行C列的地图,地图的每一个方格可能是'#', '+', '-', '|', '.', 'S', 'T'七个字符中的一个,分别表示如下意思:
  '#': 任何时候玩家都不能移动到此方格;
  '+': 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
  '-': 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非'#'方格移动一格;
  '|': 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非'#'方格移动一格;
  '.': 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为'#',则玩家不能再移动;
  'S': 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
  'T': 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格。
  此外,玩家不能移动出地图。
  请找出满足下面两个性质的方格个数:
  1. 玩家可以从初始位置移动到此方格;
  2. 玩家不可以从此方格移动到目标位置。
输入格式
  输入的第一行包括两个整数R 和C,分别表示地图的行和列数。(1 ≤ R, C ≤ 50)。
  接下来的R行每行都包含C个字符。它们表示地图的格子。地图上恰好有一个'S'和一个'T'。
输出格式
  如果玩家在初始位置就已经不能到达终点了,就输出“I'm stuck!”(不含双引号)。否则的话,输出满足性质的方格的个数。
样例输入
5 5
--+-+
..|#.
..|##
S-+-T
####.
样例输出
2
样例说明
  如果把满足性质的方格在地图上用'X'标记出来的话,地图如下所示:
--+-+
..|#X
..|##
S-+-T
####X
 */
public class Main5 {
	// 代表输入的字符
	static char map[][];
	// 偏移量,上、右、下、左
	static int[] dx = { -1, 0, 1, 0 };
	static int[] dy = { 0, 1, 0, -1 };
	// 从起点能够到达的点的标识
	static boolean[][] vis1;
	// 能够到达终点的点的标识
	static boolean[][] vis2;

	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);

		int R = input.nextInt();
		int C = input.nextInt();

		map = new char[R][C];
		vis1 = new boolean[R][C];
		vis2 = new boolean[R][C];
		int S_i = 0, S_j = 0, T_i = 0, T_j = 0;

		for (int i = 0; i < R; i++) {
			String strline = input.next();// 获取一行字符串
			for (int j = 0; j < C; j++) {
				map[i][j] = strline.charAt(j);// 获取对应的字符,并获得S和T的位置
				if (map[i][j] == 'S') {
					S_i = i;
					S_j = j;
				} else if (map[i][j] == 'T') {
					T_i = i;
					T_j = j;
				}
			}
		}
		input.close();

		dfs1(S_i, S_j);
		dfs2(T_i, T_j);
		
		// 如果起点无法到终点
		if (!vis1[T_i][T_j]) {
			System.out.println("I'm stuck!");
		} else {
			// 统计能够从起点到该点且从该点也可以到终点的格子数量
			int res = 0;
			for (int i = 0; i < R; i++) {
				for (int j = 0; j < C; j++) {
					if (vis1[i][j] && !vis2[i][j]) {
						res++;
					}
				}
			}
			System.out.println(res);
		}

	}

	// 标记起点能够到达的节点
	private static void dfs1(int x, int y) {
		vis1[x][y] = true;
		for (int i = 0; i < 4; i++) {
			int r = x + dx[i];
			int c = y + dy[i];
			if (r < 0 || c < 0 || r >= map.length || c >= map[0].length || map[r][c] == '#' || vis1[r][c]) {
				continue;
			}
			// 判断从(x,y)是否能够到达(r,c),若不能到达,则递归结束
			if (check(x, y, i)) {
				dfs1(r, c);
			}
		}
	}

	/**
	 * 检测从(x,y)是否能够移动到(r,c),(r,c)由i索引的dx、dy定位
	 * 
	 * @param x
	 * @param y
	 * @param i
	 * @return
	 */
	private static boolean check(int x, int y, int i) {
		char c = map[x][y];

		if (c == 'S' || c == 'T' || c == '+') {
			return true;
		} else if (c == '|' && (i == 0 || i == 2)) {
			return true;
		} else if (c == '-' && (i == 1 || i == 3)) {
			return true;
		} else if (c == '.' && i == 2) {
			return true;
		} else {
			return false;
		}

	}

	/**
	 * 标记终点能够到达的节点
	 * 
	 * @param x
	 * @param y
	 */
	private static void dfs2(int x, int y) {
		vis2[x][y] = true;
		for (int i = 0; i < 4; i++) {
			int r = x + dx[i];
			int c = y + dy[i];
			// 边界条件,以及判断是否已经访问过了
			if (r < 0 || c < 0 || r >= map.length || c >= map[0].length || map[r][c] == '#' || vis2[r][c]) {
				continue;
			}
			// 检测能否通过(r,c)到达(x,y),若不能到达,则递归结束
			if (check(r, c, i ^ 2)) {// 这里通过异或运算,得到的顺序和上面刚好相反,即上面是按照上、右、下、左顺序搜索,而这里就是下、左、上、右判断!
				dfs2(r, c);
			}
		}
	}

}

代码分析

先初始化map二维数组,并得到S和T的位置。然后dfs1深搜从初始位置可以到达的全部方格;dfs2深搜可以移动到目标位置的全部方格。最后根据规则输出。
dfs1尝试上下左右四个方向,探索是否有移动可能。
1.先判断目标位置是否可以到达

 if (r < 0 || c < 0 || r >= map.length || c >= map[0].length || map[r][c] == '#' || vis1[r][c]) {
                continue;
            }

2.判断当前位置(x,y)是否可以进行i移动

if (check(x, y, i)) {
                dfs1(r, c);
            }

dfs2和dfs1功能相似。
dfs1考察从当前节点是否可以向四个方向移动,dfs2考察从四周是否可以到达当前节点。
dfs2
我们通过

   int r = x + dx[i];
   int c = y + dy[i];

获得四周节点,而check时需要检查,从四周节点是否可以到达当前节点,故第三个参数检查相反的移动方向是否可以。

  if (check(r, c, i ^ 2)) {// 这里通过异或运算,得到的顺序和上面刚好相反,即上面是按照上、右、下、左顺序搜索,而这里就是下、左、上、右判断!
                dfs2(r, c);
            }

本题只是使用了和图深度遍历同样的思想,并不是考察图结构的深度遍历。只是深度遍历二维数组。
一个基本模板如下:

import java.util.Random;

public class TwoArrDfs {
    static Random random = new Random();
    private static void print(int[][] arrtwo) {
        for(int i = 0; i < arrtwo.length; i++){
            for(int j = 0; j < arrtwo[i].length; j++){
                System.out.print(arrtwo[i][j]+" ");
            }
            System.out.println();
        }
    }
    private static void dfs(int[][] arrtwo, int i, int j) {
        arrtwo[i][j] = random.nextInt(20)+1;
        //是否可以向上走
        if(i > 0 && arrtwo[i-1][j]==0){
            dfs(arrtwo, i-1, j);
        }
        //是否可以向下走
        if(i < arrtwo.length - 1 && arrtwo[i+1][j]==0){
            dfs(arrtwo, i+1, j);
        }
        //是否可以向左走
        if(j > 0 && arrtwo[i][j-1]==0){
            dfs(arrtwo, i, j-1);
        }
        //是否可以向右走
        if(j < arrtwo[0].length - 1 && arrtwo[i][j+1]==0){
            dfs(arrtwo, i, j+1);
        }
    }
    public static void main(String[] args) {
        int[][] arr = new int[4][5];
        dfs(arr,0,0);
        print(arr);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/437792.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JS使用方式

JS是解释性语言&#xff0c;所以不需要搭建类似C#/Java之类的开发运行环境&#xff0c;因为他们是编译型语言。JS一般运行在浏览器中或者node环境中&#xff0c;这里都是JS引擎的功劳。 node环境使用 推荐使用nvm管理node版本&#xff0c;nrm管理代理地址。 安装node&#xf…

腾讯云服务器和阿里云服务器哪家更优惠?2024价格对比

2024年阿里云服务器和腾讯云服务器价格战已经打响&#xff0c;阿里云服务器优惠61元一年起&#xff0c;腾讯云服务器61元一年&#xff0c;2核2G3M、2核4G、4核8G、4核16G、8核16G、16核32G、16核64G等配置价格对比&#xff0c;阿腾云atengyun.com整理阿里云和腾讯云服务器详细配…

【蓝桥杯基础算法】dfs(上)组合数,全排列

刚接触算法&#xff0c;有没有被递归又循环的dfs吓到&#xff1f;没关系&#xff0c;几个例题就可以彻底掌握&#xff01; 1.全排列 1-n的全排列,如输入3&#xff0c;按顺序对1-3进行排列 //枚举 #include<iostream> #include<algorithm> #include<cstring>…

【Linux基础(二)】进程管理

学习分享 1、程序和进程1.1、程序1.2、进程和进程ID 2、Linux下的进程结构3、init进程4、获取进程标识5、fork系统调用5.1、fork函数实例分析 6、进程的特性7、在Linux下进程指令7.1、终止进程指令7.2、查看进程指令&#xff1a;7.3、以树状图列出进程 8、多进程运行异常情况8.…

【Spring云原生系列】Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合!

&#x1f389;&#x1f389;欢迎光临&#xff0c;终于等到你啦&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;持续更新的专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &a…

2024年抖店新商家自学全套教程,完整版店铺操作流程,如下!

我是王路飞。 想做一个项目的话&#xff0c;就要先了解其完整的流程是怎样的。 做抖店也不例外&#xff0c;没开店的就先了解下抖店的基本信息和大概运营流程&#xff1b;开过店的就先让自己入门并把流程跑通&#xff0c;如此才有承接后续渠道和资源的能力。 今天这篇文章专…

计算机网络:应用层知识点汇总

文章目录 一、网络应用模型二、域名系统&#xff08;DNS&#xff09;三、文本传输协议&#xff08;FTP&#xff09;四、电子邮件五、万维网和HTTP协议 一、网络应用模型 p2p也就是对等模型 二、域名系统&#xff08;DNS&#xff09; 我们知道&#xff0c;随着人们建立一个网站…

【机器学习】【决策树】分类树|回归树学习笔记总结

决策树算法概述 基本概念 决策树&#xff1a;从根节点开始一步步走到叶子节点&#xff0c;每一步都是决策过程 对于判断的先后顺序把控特别严格 一旦将判断顺序进行变化则最终的结果将可能发生改变 往往将分类效果较佳的判断条件放在前面&#xff0c;即先初略分在进行细节分…

python中的文件操作2

文件遍历 在Python中&#xff0c;遍历文件通常指的是逐行读取文件中的内容。这种方式对于处理大型文件特别有用&#xff0c;因为它不需要一次性将整个文件加载到内存中。下面是几种常见的遍历文件内容的方法&#xff1a; 1. 使用with语句和for循环 这是最推荐的方式&#xf…

[Java安全入门]三.URLDNS链

一.前言 在初步学习java的序列化和反序列化之后&#xff0c;这里学习java反序列化漏洞的一个利用链&#xff0c;也是比较基础的一条链。 由于URLDNS不需要依赖第三方的包&#xff0c;同时不限制jdk的版本&#xff0c;所以通常用于检测反序列化的点。 二.代码展开分析 构造链 …

appium解锁android真机系统的屏幕

在使用appium进行app自动化操作的过程中&#xff0c;经常遇到的第一个难题就是如何解锁系统屏幕&#xff0c;也就是亮屏解锁。 实际上解决办法如下&#xff1a;在desired_capabilities中增加两个参数unlockType和unlockKey&#xff0c;类似的示例代码如下&#xff1a; desire…

2024年腾讯云优惠政策_腾讯云服务器特价购买活动入口

腾讯云优惠活动2024新春采购节活动上线&#xff0c;云服务器价格已经出来了&#xff0c;云服务器61元一年起&#xff0c;配置和价格基本上和上个月没什么变化&#xff0c;但是新增了8888元代金券和会员续费优惠&#xff0c;腾讯云百科txybk.com整理腾讯云最新优惠活动云服务器配…

Express学习(二)

Express路由 路由的概念 现实生活中的 路由&#xff1a;例如我们在拨打10086的时候&#xff0c;会让我们按指定的按键选择对应的服务&#xff0c;这里的路由就是按键和服务之间的映射关系。 Express中的路由 在Express中&#xff0c;路由指的是客户端的请求与服务器处理函数…

基于STC系列单片机实现PNP型三极管S8550驱动共阳数码管或NPN型三极管S8050驱动共阴数码管功能

Digitron.c #include "Digitron.h" //#include "Key.h" #define uchar unsigned char//自定义无符号字符型为uchar #define uint unsigned int//自定义无符号整数型为uint //uchar code DigitronBitCodeArray[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x…

AOP理解

AOP就是面向特定的方法进行编程&#xff0c;在不改动原始方法的基础上&#xff0c;可以增强原始方法的功能&#xff0c;或者改变某些功能&#xff0c;我们可以通过AOP记录数据库的操作日志 AOP的底层实现就是动态代理技术&#xff0c;在执行原始方法前&#xff0c;生成一个代理…

【Linux】开始使用gdb吧!

开始使用gdb吧&#xff01; 1 下载安装2 开始使用3 实践运用补充一下 print 的 功能 &#xff08;类似监视窗口的作用&#xff09;和显示堆栈的功能Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff01;下一篇文章见&#xff01;&am…

JavaScript基础4之原型的原型继承、原型链和理解对象的数据属性、访问器属性

JavaScript基础 原型原型继承问题解决 原型链isPrototypeOf()Object.getPrototypeOf() 理解对象数据属性访问器属性 原型 原型继承 继承是面向对象编程的另一个特征&#xff0c;通过继承进一步提升代码封装的程度&#xff0c;JavaScript中大多是借助原型对象实现继承的特性。…

计算机基础专升本笔记十四-计算机网络基础(一)

计算机基础专升本笔记十四-计算机网络基础&#xff08;一&#xff09; 一、计算机网络的发展历程 第一代计算机网络&#xff08;数据通信&#xff09; 以数据通信为主的第一代计算机网络。主要是指美国军方用于防控系统的一种联机系统。它只是计算机网络的雏形。 第二代计算…

2022年浙江省职业院校技能大赛信息安全管理与评估 理论题答案

培训、环境、资料 公众号&#xff1a;Geek极安云科 网络安全群&#xff1a;775454947极安云科专注于技能提升&#xff0c;赋能 2024年广东省高校的技能提升&#xff0c;在培训中我们的应急响应环境 成功押题成功&#xff0c;知识点、考点、内容完美还原大赛赛题环境&#xff0c…

比肩Gen-2,全新开源文生视频模型

著名开源平台Stability.ai在官网宣布&#xff0c;推出全新文生视频的扩散模型Stable Video Diffusion&#xff0c;已开源了该项目并公布了论文。 据悉&#xff0c;用户通过文本或图像就能生成高精准&#xff0c;14帧和25帧的短视频。目前&#xff0c;Stable Video Diffusion处…