17年真题 蓝桥杯 javaC 青蛙跳 第九题-bfs(包含蓝桥杯 算法提高 学霸的迷宫-bfs)
标题:青蛙跳杯子
X星球的流行宠物是青蛙,一般有两种颜色:白色和黑色。
X星球的居民喜欢把它们放在一排茶杯里,这样可以观察它们跳来跳去。
如下图,有一排杯子,左边的一个是空着的,右边的杯子,每个里边有一只青蛙。
WWWBBB
其中,W字母表示白色青蛙,B表示黑色青蛙,表示空杯子。
X星的青蛙很有些癖好,它们只做3个动作之一:
1. 跳到相邻的空杯子里。
2. 隔着1只其它的青蛙(随便什么颜色)跳到空杯子里。
3. 隔着2只其它的青蛙(随便什么颜色)跳到空杯子里。
对于上图的局面,只要1步,就可跳成下图局面:
WWWBBB
本题的任务就是已知初始局面,询问至少需要几步,才能跳成另一个目标局面。
输入为2行,2个串,表示初始局面和目标局面。
输出要求为一个整数,表示至少需要多少步的青蛙跳。
例如:
输入:
WWBB
WWBB
则程序应该输出:
2
再例如,
输入:
WWWBBB
BBB*WWW
则程序应该输出:
10
我们约定,输入的串的长度不超过15
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
package javaC;
import java.util.*;
public class _9青蛙跳杯子_BFS {
/**
* @param args
*/
static String str1;
static String str2;
static List<String> list = new LinkedList<String>();
static Map<String, Boolean> vis = new HashMap<String, Boolean>();//用HashMap标记出现过的情况
static class Node{
int step = 0;
String str;
public Node(String str,int step){
this.str = str;
this.step = step;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
str1 = input.next();
str2 = input.next();
System.out.println(bfs());
}
private static int bfs() {
// TODO Auto-generated method stub
Queue<Node> queue = new LinkedList<Node>();
Node node = new Node(str1,0);//将初始状态加入到Node节点初始化
queue.add(node);//然后再将改节点加入队列中
vis.put(node.str, true);//再把该初始节点的状态用HashMap记录为已经使用过了
while(queue.size()!=0){//如果队列的大小不为0
node = queue.poll();//出队
if(isOk(node.str))//判断这字符串是否与目标字符串相同
return node.step;//返回跳到这一个字符串需要的次数
char[] str = node.str.toCharArray();//将出队列的这个节点中的str字符串转换成字符数组
int step = node.step;//获取这一字符串的步数
for(int i=0;i<str.length;i++){//遍历这个字符串
if(str[i]=='*') continue;//遍历到'*',跳过这个,继续下一个循环
for(int j=-3;j<=3;j++){//青蛙跳空杯有6种情况,左3,左2,左1,右1,右2,右3,遍历这六种情况
if(i+j<0 || i+j>=str.length || j==0 || str[i+j]!='*') continue;//判断遍历越界,跳过这个,继续下一个循环
str = swap(str,i,j);//青蛙跳空杯,交换str串的i和j字符,再将此新字符串赋给str字符串
node = new Node(String.valueOf(str),step+1);//将这个新的字符串,步数+1,初始化一个新节点
if(!vis.containsKey(node.str)){//判断这个新的字符串以前是否出现过
queue.add(node);//没有出现过,将这个node节点加入队列
list.add(node.str);//将node.str加入list中
vis.put(node.str, true);//设置这个字符串已经出现过
}
str = swap(str,i,j);//出现过,将字符串复原,继续循环
}
}
}
return -1;//如果队列为0,还没出现目标字符串,返回-1
}
private static char[] swap(char[] str, int i, int j) {
// TODO Auto-generated method stub
char temp = str[i];
str[i] = str[j+i];
str[j+i] = temp;
return str;
}
//判断str和目标字符串str2是否相同
private static boolean isOk(String str) {
// TODO Auto-generated method stub
if(str2.equalsIgnoreCase(String.valueOf(str)))
return true;
else
return false;
}
}
试题 算法提高 学霸的迷宫
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗。但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要进城堡必须得先通过迷宫。因为班长还有妹子要陪,磨刀不误砍柴功,他为了节约时间,从线人那里搞到了迷宫的地图,准备提前计算最短的路线。可是他现在正向妹子解释这件事情,于是就委托你帮他找一条最短的路线。
输入格式
第一行两个整数n, m,为迷宫的长宽。
接下来n行,每行m个数,数之间没有间隔,为0或1中的一个。0表示这个格子可以通过,1表示不可以。假设你现在已经在迷宫坐标(1,1)的地方,即左上角,迷宫的出口在(n,m)。每次移动时只能向上下左右4个方向移动到另外一个可以通过的格子里,每次移动算一步。数据保证(1,1),(n,m)可以通过。
输出格式
第一行一个数为需要的最少步数K。
第二行K个字符,每个字符∈{U,D,L,R},分别表示上下左右。如果有多条长度相同的最短路径,选择在此表示方法下字典序最小的一个。
样例输入
Input Sample 1:
3 3
001
100
110
Input Sample 2:
3 3
000
000
000
样例输出
Output Sample 1:
4
RDRD
Output Sample 2:
4
DDRR
数据规模和约定
有20%的数据满足:1<=n,m<=10
有50%的数据满足:1<=n,m<=50
有100%的数据满足:1<=n,m<=500。
package 算法提高;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class 学霸的迷宫_BFS {
/**
* @param args
*/
public static int[][] move = {{-1,0},{1,0},{0,-1},{0,1}};//表示上下左右
public static String[] onePath = {"U","D","L","R"};//表示上下左右
static class point{//内部类
int x;//当前顶点的横坐标
int y;//当前顶点的纵坐标
int step;//行走到当前顶点的步数
String path;//行走到当前顶点的具体路径
point(int x,int y,int step,String path){
this.x = x;
this.y = y;
this.step = step;
this.path = path;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int m = input.nextInt();
input.nextLine();
String[] A = new String[n];
for(int i=0;i<n;i++){
A[i] = input.next();
}
bfs(A,m);
}
private static void bfs(String[] A, int m) {
// TODO Auto-generated method stub
int[][] matrix = getMatrix(A,m);
Queue<point> queue = new LinkedList<point>();
queue.add(new point(1,1,0,""));//表示从顶点(1,1)出发
int minStep = Integer.MAX_VALUE;//用于记录到达最终顶点所需最少步数
String minPath = "";//用于记录到达最终顶点路径的最小字典序序列
while(queue.size()!=0){
point begin = queue.poll();//第一个元素出队
if(begin.x == matrix.length-1 && begin.y == matrix[0].length-1){//这个位置是终点
if(minStep > begin.step){//如果minStep>begin.step,获取最小step和最小path
minStep = begin.step;
minPath = begin.path;
}
else if(minStep == begin.step){//如果步数相同,获取字典序最小
if(judge(minPath,begin.path))//若minPath>begin.path的字典序
minPath = begin.path;//把begin.path赋给minPath
}
System.out.println(minStep+"\n"+minPath);//找到最优结果,输出
return;
}
for(int i=0;i<4;i++){
int x = begin.x + move[i][0];
int y = begin.y + move[i][1];
int step = begin.step + 1;
String path = begin.path + onePath[i];
point temp = new point(x,y,step,path);
if(check(matrix,temp)){//判断这个顶点temp是可到达的顶点时
queue.add(temp);
matrix[x][y] = 1;//到达该顶点后,标记该顶点不可到达
}
}
}
return;
}
//判断这个位置是否可以到达
private static boolean check(int[][] matrix, point temp) {
// TODO Auto-generated method stub
int n = matrix.length-1;
int m = matrix[0].length-1;
if(temp.x<1 || temp.x>n || temp.y<1 || temp.y>m || matrix[temp.x][temp.y]==1)
return false;
return true;
}
//判断最小字典序
private static boolean judge(String A, String B) {
// TODO Auto-generated method stub
char[] arrayA = A.toCharArray();
char[] arrayB = B.toCharArray();
for(int i=0;i<A.length();i++)
if(arrayA[i] < arrayB[i])
return false;
return true;
}
//将字符串数组,转换成int类型的数组
private static int[][] getMatrix(String[] A, int m) {
// TODO Auto-generated method stub
int[][] matrix = new int[A.length+1][m+1];
for(int i=0;i<A.length;i++){
char[] arrayA = A[i].toCharArray();
for(int j=0;j<m;j++){
matrix[i+1][j+1] = arrayA[j]-'0';
}
}
return matrix;
}
}
ps:由于之前没怎么用过bfs,这一次第一次正式用到bfs算法,不太会,所以参考了别博主的代码,然后又从蓝桥杯练习系统上找了一个类似的题目摸索了一下。感觉有一点点略懂了,但是还是很生疏,所以特此记录下来,方便后面学习的时候查阅。
pps:因为不太会,所以注释写的有点多QAQ