求任意大小矩阵两点之间的最短路径(回溯)
今天在某个公司的笔试题目上做到了一个题目:
任意给定两个正半轴坐标点,求最短路径。
因为短时间很难写出动态规划,而且自己对动态规划的理解也不够深刻。所以能想到的就是回溯。
首先:给定起点和终点,求最短路径,一共有八个方向
解题参考就是 回溯算法(马踏棋盘)
如果每次都在原有矩阵上跑,开销太大了,于是采用截取范围的思想,将起
点和终点作为新矩阵的顶点进行截取,创建新矩阵,更新坐标,然后在此基
础上找一个最短路径出来
package com.test;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Stack;
public class findShortWay {
//定义从上开始,顺时针跑八个方向
private int rowStep[] = {-1,-1,0,1,1,1,0,-1};
private int colStep[] = {0,1,1,1,0,-1,-1,-1};
//方向映射关系
private String stepMappint[] ={"U","UR","R","RD","D","LD","L","UL"};
Stack<Integer> minStack = null;
private int endX,endY;
public static void main(String[] args) {
new findShortWay().dispatcherMethod();
}
//字符转数字 因为此公司是横坐标是字母
//本代码没有做输入转数字的处理
public int char2Int(char c) throws IllegalArgumentException{
if(c >= 'a' && c <= 'z'){
return c-'a';
}else if(c >= 'A' && c<= 'Z'){
return c-'A';
}else{
throw new IllegalArgumentException("输入不是字母");
}
}
//初始化
private void init(int arr[][]){
for(int i=0;i<arr.length;i++){
for (int j = 0; j < arr[i].length; j++) {
arr[i][j] = 0;
}
}
}
/**
* 核心处理类(调度器)
*/
public void dispatcherMethod(){
int startX,startY;
//输入起始坐标和结束坐标
Scanner in = new Scanner(System.in);
startX=in.nextInt();
startY=in.nextInt();
endX=in.nextInt();
endY=in.nextInt();
//处理输入异常
if(startX==endX && startY==endY){
System.out.println("原地不动");
return;
}else if(startX<0 || endX<0 || startY<0 || endY<0){
System.out.println("输入异常");
return;
}
//构建最小矩阵
int arr[][] = new int[Math.abs(startX-endX)+1][Math.abs(startY-endY)+1];
init(arr);
//更新坐标
int num = getMin(startX,endX);
startX = subtrac(startX,num);
endX = subtrac(endX,num);
num = getMin(startY,endY);
startY = subtrac(startY,num);
endY = subtrac(endY,num);
//定义中转栈
Stack<Integer> stack = new Stack<Integer>();
horseRun(stack,arr,startX,startY);
realShortWay();
}
private int getMin(int x,int y){
return x>y?y:x;
}
private int subtrac(int x,int y){
return x-y;
}
private void horseRun(Stack<Integer> stack,int arr[][],int startX,int startY){
arr[startX][startY]=1;
//遍历八个需要走的路径
for(int i=0;i<8;i++){
//试步操作
startX +=rowStep[i];
startY +=colStep[i];
//判断是否可以走
if(canWalk(arr,startX,startY)){
//每次符合的压栈
stack.push(i);
//判断是否到终点
if(startX==endX && startY==endY){
Stack<Integer> newStack = new Stack<Integer>();
newStack.addAll(stack);
//判断是否是第一次找到路径,或者是否比最短路径短
if(minStack==null || stack.size()<minStack.size()){
//如果跑到终点,和最小栈的长度进行比较,更替
minStack = newStack;
}
}else{
horseRun(stack,arr,startX,startY);
}
stack.pop();
}
startX -=rowStep[i];
startY -=colStep[i];
}
arr[startX][startY]=0;
}
//判断本位置是否符合走步要求
private boolean canWalk(int arr[][],int x,int y){
if(x<0 || x>=arr.length || y<0 || y>=arr[x].length){
return false;
}
if(arr[x][y] != 0){
return false;
}
return true;
}
//语言描述真实最短路径
public void realShortWay(){
if(minStack == null){
System.out.println("迷宫没有找到解");
return;
}
Iterator<Integer> minStackIter = minStack.iterator();
while(minStackIter.hasNext()){
Integer i = minStackIter.next();
System.out.print(stepMappint[i]+" ");
}
System.out.println();
}
}
易错点:
1. 创建新矩阵数组的时候容易忘记终点和起点的坐标做差会少计算一个单元的数值。
2. 因为是解算法题,所以是没有必要有提示语句的,此处是为了程序方便理解
3. 更新坐标那里,我还没有想到更好的方法,如果有人想到了请给我发邮件quphi@163.com
程序真长。。还没有加字符转换功能呢~还是不符合题意。因为非常简单,考察字符串的拆分,大家可以自己尝试实现