题目描述
爱丽丝刚从一处地下迷宫中探险归来,你能根据她对于自己行动路径的回忆,帮她画出迷宫地图吗?
迷宫地图是基于二维网格的。爱丽丝会告诉你一系列她在迷宫中的移动步骤,每个移动步骤可能是上下左右四个方向中的一种,表示爱丽丝往这个方向走了一格。你需要根据这些移动步骤给出一个迷宫地图,并满足以下条件:
1、爱丽丝能在迷宫内的某个空地开始,顺利的走完她回忆的所有移动步骤。
2、迷宫内不存在爱丽丝没有走过的空地。
3、迷宫是封闭的,即可通过墙分隔迷宫内与迷宫外。任意方向的无穷远处视为迷宫外,所有不与迷宫外联通的空地都视为是迷宫内。(迷宫地图为四联通,即只有上下左右视为联通)
4、在满足前面三点的前提下,迷宫的墙的数量要尽可能少。
输入格式
第一行一个正整数 N,表示爱丽丝回忆的步骤数量。
接下来一行 N 个英文字符,仅包含 UDLR 四种字符,分别表示上(Up)、下(Down)、左(Left)、右(Right)。
输出格式
请通过字符画的形式输出迷宫地图。迷宫地图可能包含许多行,用字符 ‘*’ 表示墙,用 ‘ ’(空格)表示非墙。
你的输出需要保证以下条件:
1、至少有一行第一个字符为 ‘*’。
2、第一行至少有一个字符为 ‘*’。
3、每一行的最后一个字符为 ‘*’。
4、最后一行至少有一个字符为 ‘*’。
样例输入
17 UUUULLLLDDDDRRRRU
样例输出
***** * * * *** * * *** * * *** * * * *****
提示
爱丽丝可以把第六行第六个字符作为起点。
外墙墙墙墙墙外
墙内内内内内墙
墙内墙墙墙内墙
墙内墙墙墙内墙
墙内墙墙墙内墙
墙内内内内内墙
外墙墙墙墙墙外
对于所有数据,0 < N ≤ 100.
暴躁开干!
题目:一哥们玩迷宫,迷宫所有路他都走过,把迷宫画出来
输入:移动步骤
输出:矩阵地图
解题:1.最外层墙包裹的是迷宫空间(迷宫内)
2.最外层墙外是(迷宫外)
3.迷宫内有墙和路,且迷宫空间被墙和路填满
思路:就是有三种状态的二维矩阵嘛,走过的,墙,迷宫外。
第一步:画地图你要不要纸!要纸你到底拿多大可以保证纸一定画得下你的地图!所以第一步决定拿多大的纸很重要!
不同的移动步骤围成的迷宫肯定不同,题目条件给了输入总步骤不大于一百,那么假设极端条件,一直向一个方向走,二维数组的最大边的长103,头尾两个墙加100步加初始位置1,好了你要么上下左右走,老子上下左右的空间都开到超过103,绝对装得下这个地图!暴躁!我直接开300*300的二维数组!从中间开始走稳了!
static char[][] table = new char[300][300];
纸能画下地图了,但是输出的时候你得修剪一下你的纸的大小,修剪成刚好画下你的图的大小,定义maxx,minx,maxy,miny来维护地图的长和宽,画完之后遍历四个点坐标内的数据就是地图了
static int x = 150;
static int y = 150;
static int maxx = 151;
static int minx = 149;
static int maxy = 151;
static int miny = 149;
第二步:开始画!画三种不同的东西拿三只不同颜色的笔画当然是最简单啦!
纸摆好!
// 初始化大地图全为走过的
int n = table.length;
int m = table[0].length;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
table[i][j]= ' ';
}
}
移动步骤拿来!
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
String empty = sc.next();
char[] chars = empty.toCharArray();
上笔!路‘*’ 走过‘1’ 画!
// 初始化第一步 真实走过标记为1 墙为*
table[y][x] = '1';
table[y+1][x] = '*';
table[y-1][x] = '*';
table[y][x+1] = '*';
table[y][x-1] = '*';
//遍历移动步骤画出路和路边的墙
for (char asc : chars) {
if (asc == 'U') {
up();
} else if (asc == 'L') {
left();
} else if (asc == 'D') {
down();
} else if (asc == 'R'){
right();
}
// map();
}
脸朝向的前左右都设为墙,注意哦,是脸朝向!你脸向的是左和脸向右,你的前左右是不同的,想象一下。
public static void up(){
y--;
table[y][x] = '1';
if (table[y-1][x] != '1'){
table[y-1][x] = '*';
}
if (table[y][x-1] != '1'){
table[y][x-1] = '*';
}
if (table[y][x+1] != '1'){
table[y][x+1] = '*';
}
miny = Math.min(y-1,miny);
}
public static void down(){
y++;
table[y][x] = '1';
if (table[y+1][x] != '1'){
table[y+1][x] = '*';
}
if (table[y][x-1] != '1'){
table[y][x-1] = '*';
}
if (table[y][x+1] != '1'){
table[y][x+1] = '*';
}
maxy = Math.max(y+1,maxy);
}
public static void left(){
x--;
table[y][x] = '1';
if (table[y+1][x] != '1'){
table[y+1][x] = '*';
}
if (table[y-1][x] != '1'){
table[y-1][x] = '*';
}
if (table[y][x-1] != '1'){
table[y][x-1] = '*';
}
minx = Math.min(x-1,minx);
}
public static void right(){
x++;
table[y][x] = '1';
if (table[y+1][x] != '1'){
table[y+1][x] = '*';
}
if (table[y-1][x] != '1'){
table[y-1][x] = '*';
}
if (table[y][x+1] != '1'){
table[y][x+1] = '*';
}
maxx = Math.max(x+1,maxx);
}
画完了!剪纸!就是大图里遍历给定区间内的数据,保存到另一个二维数组里
//最大最小的x和y维护最小矩阵,取小矩阵
retablemap = new char[maxy-miny+1][maxx-minx+1];
remap();
public static void remap(){
for (int i = miny; i <= maxy; i++) {
for (int j = minx; j <= maxx; j++) {
retablemap[i-miny][j-minx] = table[i][j];
}
}
}
到这里,用样例测一下你画出来的图长这样
有没发现中间有个位置空了!因为这个位置和路不相邻,不能形成墙。
所以来第三步!
题意要求,迷宫内那么是路要么是墙,路已经是按输入的步骤画出来的没问题,所以地图内空的位置一定为墙。
那就是说我只要区分迷宫内和迷宫外,再把迷宫内空着的位置填墙就稳了!
那怎么区分迷宫内和迷宫外呢
第三只笔来!我把迷宫外的格子全部填2,剩下没填的地方一定就是迷宫内了。
这里用到了感染算法!感染算法就是如果我是人就把我上毒,我会感染与我相邻的人,迭代一下,迭代条件如果你旁边是人,就能被感染,如果不是人,感染不上;
这里的题意可以理解为从边开始向内感染直到碰上墙;
int retablemapn = retablemap.length;
int retablemapm = retablemap[0].length;
//感染地图外侧 能被矩阵边感染的一定是地图外侧,外侧标记为2,第一行最后一行感染
for (int i = 0; i < retablemapm; i++) {
if (retablemap[0][i] == ' '){
infect(retablemap,0,i,retablemapn,retablemapm);
}
if (retablemap[retablemapn-1][i] == ' '){
infect(retablemap,retablemapn-1,i,retablemapn,retablemapm);
}
}
//第一列最后一列感染
for (int i = 0; i < retablemapn; i++) {
if (retablemap[i][0] == ' '){
infect(retablemap,i,0,retablemapn,retablemapm);
}
if (retablemap[i][retablemapm-1] == ' '){
infect(retablemap,i,retablemapm-1,retablemapn,retablemapm);
}
}
//感染算法
public static void infect(char[][] m,int i,int j,int N,int M){
if (i < 0 || i>=N || j<0 || j>=M ||m[i][j] != ' '){
return;
}
m[i][j] = '2';
infect(m,i+1,j,N,M);
infect(m,i-1,j,N,M);
infect(m,i,j+1,N,M);
infect(m,i,j-1,N,M);
}
看一下变化
根据移动步骤画出来的图
感染迷宫外
好了,到这里把自己定的标记擦掉,填上符合题目的标记
屡一下:自己定的 2为迷宫外,1为路,*为墙,空格为迷宫内没办法通过路径渲染到的地方又因为它在迷宫内,所以也要变为墙
题目要的 空格为迷宫外 把我们的2改为空格
空格为路径 把我们的1改为空格
*为墙 把我们的 *不变,空格改*
// 遍历二维数组,填充墙‘ ’改为*,路标记1改‘ ’,地图外侧标记2改为‘ ’
for (int i = 0; i < retablemapn; i++) {
for (int j = 0; j < retablemapm; j++) {
if (retablemap[i][j] == '1') {
retablemap[i][j] = ' ';
} else if (retablemap[i][j] == ' ') {
retablemap[i][j] = '*';
} else if (retablemap[i][j] == '2') {
retablemap[i][j] = ' ';
}
}
}
打印填充墙后的图
// System.out.println("-----------------");
for (int i = 0; i < retablemapn; i++) {
for (int j = 0; j < retablemapm; j++) {
System.out.print(retablemap[i][j]);
}
System.out.println();
}
}
上测试结果
上测试地址
https://www.lanqiao.cn/problems/2150/learning/
上完整代码
import java.util.Scanner;
/**
题目描述
爱丽丝刚从一处地下迷宫中探险归来,你能根据她对于自己行动路径的回忆,帮她画出迷宫地图吗?
迷宫地图是基于二维网格的。爱丽丝会告诉你一系列她在迷宫中的移动步骤,每个移动步骤可能是上下左右四个方向中的一种,表示爱丽丝往这个方向走了一格。你需要根据这些移动步骤给出一个迷宫地图,并满足以下条件:
1、爱丽丝能在迷宫内的某个空地开始,顺利的走完她回忆的所有移动步骤。
2、迷宫内不存在爱丽丝没有走过的空地。
3、迷宫是封闭的,即可通过墙分隔迷宫内与迷宫外。任意方向的无穷远处视为迷宫外,所有不与迷宫外联通的空地都视为是迷宫内。(迷宫地图为四联通,即只有上下左右视为联通)
4、在满足前面三点的前提下,迷宫的墙的数量要尽可能少。
输入格式
第一行一个正整数 N,表示爱丽丝回忆的步骤数量。
接下来一行 N 个英文字符,仅包含 UDLR 四种字符,分别表示上(Up)、下(Down)、左(Left)、右(Right)。
输出格式
请通过字符画的形式输出迷宫地图。迷宫地图可能包含许多行,用字符 ‘*’ 表示墙,用 ‘ ’(空格)表示非墙。
你的输出需要保证以下条件:
1、至少有一行第一个字符为 ‘*’。
2、第一行至少有一个字符为 ‘*’。
3、每一行的最后一个字符为 ‘*’。
4、最后一行至少有一个字符为 ‘*’。
样例输入
17
UUUULLLLDDDDRRRRU
样例输出
*****
* *
* *** *
* *** *
* *** *
* *
*****
提示
爱丽丝可以把第六行第六个字符作为起点。
外墙墙墙墙墙外
墙内内内内内墙
墙内墙墙墙内墙
墙内墙墙墙内墙
墙内墙墙墙内墙
墙内内内内内墙
外墙墙墙墙墙外
对于所有数据,0 < N ≤ 100.
*/
public class T_05 {
//初始点100,100
static int x = 150;
static int y = 150;
static int maxx = 151;
static int minx = 149;
static int maxy = 151;
static int miny = 149;
static char[][] table = new char[300][300];
static char[][] retablemap;
public static void main(String[] args) {
// 初始化大地图全为走过的
int n = table.length;
int m = table[0].length;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
table[i][j]= ' ';
}
}
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
String empty = sc.next();
char[] chars = empty.toCharArray();
// 初始化第一步 真实走过标记为1 墙为*
table[y][x] = '1';
table[y+1][x] = '*';
table[y-1][x] = '*';
table[y][x+1] = '*';
table[y][x-1] = '*';
// x table[miny][minx] table[miny][maxx]
// 0->200 99 101
// y |
// 200 101
// table[maxy][minx] table[maxy][maxx]
//遍历移动步骤画出路和路边的墙
for (char asc : chars) {
if (asc == 'U') {
up();
} else if (asc == 'L') {
left();
} else if (asc == 'D') {
down();
} else if (asc == 'R'){
right();
}
// map();
}
//最大最小的x和y维护最小矩阵,取小矩阵
retablemap = new char[maxy-miny+1][maxx-minx+1];
remap();
//取最小矩阵的行和列
int retablemapn = retablemap.length;
int retablemapm = retablemap[0].length;
//感染地图外侧 能被矩阵边感染的一定是地图外侧,外侧标记为2,第一行最后一行感染
for (int i = 0; i < retablemapm; i++) {
if (retablemap[0][i] == ' '){
infect(retablemap,0,i,retablemapn,retablemapm);
}
if (retablemap[retablemapn-1][i] == ' '){
infect(retablemap,retablemapn-1,i,retablemapn,retablemapm);
}
}
//第一列最后一列感染
for (int i = 0; i < retablemapn; i++) {
if (retablemap[i][0] == ' '){
infect(retablemap,i,0,retablemapn,retablemapm);
}
if (retablemap[i][retablemapm-1] == ' '){
infect(retablemap,i,retablemapm-1,retablemapn,retablemapm);
}
}
// 遍历二维数组,填充墙‘ ’改为*,路标记1改‘ ’,地图外侧标记2改为‘ ’
for (int i = 0; i < retablemapn; i++) {
for (int j = 0; j < retablemapm; j++) {
if (retablemap[i][j] == '1') {
retablemap[i][j] = ' ';
} else if (retablemap[i][j] == ' ') {
retablemap[i][j] = '*';
} else if (retablemap[i][j] == '2') {
retablemap[i][j] = ' ';
}
}
}
打印填充墙后的图
// System.out.println("-----------------");
for (int i = 0; i < retablemapn; i++) {
for (int j = 0; j < retablemapm; j++) {
System.out.print(retablemap[i][j]);
}
System.out.println();
}
}
//感染算法
public static void infect(char[][] m,int i,int j,int N,int M){
if (i < 0 || i>=N || j<0 || j>=M ||m[i][j] != ' '){
return;
}
m[i][j] = '2';
infect(m,i+1,j,N,M);
infect(m,i-1,j,N,M);
infect(m,i,j+1,N,M);
infect(m,i,j-1,N,M);
}
//大矩阵取小矩阵
public static void remap(){
for (int i = miny; i <= maxy; i++) {
for (int j = minx; j <= maxx; j++) {
retablemap[i-miny][j-minx] = table[i][j];
}
}
}
//上 (Up)、 下 (Down)、左 (Left)、右 (Right)。
public static void up(){
y--;
table[y][x] = '1';
if (table[y-1][x] != '1'){
table[y-1][x] = '*';
}
if (table[y][x-1] != '1'){
table[y][x-1] = '*';
}
if (table[y][x+1] != '1'){
table[y][x+1] = '*';
}
miny = Math.min(y-1,miny);
}
public static void down(){
y++;
table[y][x] = '1';
if (table[y+1][x] != '1'){
table[y+1][x] = '*';
}
if (table[y][x-1] != '1'){
table[y][x-1] = '*';
}
if (table[y][x+1] != '1'){
table[y][x+1] = '*';
}
maxy = Math.max(y+1,maxy);
}
public static void left(){
x--;
table[y][x] = '1';
if (table[y+1][x] != '1'){
table[y+1][x] = '*';
}
if (table[y-1][x] != '1'){
table[y-1][x] = '*';
}
if (table[y][x-1] != '1'){
table[y][x-1] = '*';
}
minx = Math.min(x-1,minx);
}
public static void right(){
x++;
table[y][x] = '1';
if (table[y+1][x] != '1'){
table[y+1][x] = '*';
}
if (table[y-1][x] != '1'){
table[y-1][x] = '*';
}
if (table[y][x+1] != '1'){
table[y][x+1] = '*';
}
maxx = Math.max(x+1,maxx);
}
}