Knight's Shortest Path on Chessboard

后端 未结 16 1284
情深已故
情深已故 2020-11-30 16:42

I\'ve been practicing for an upcoming programming competition and I have stumbled across a question that I am just completely bewildered at. However, I feel as though it\'s

相关标签:
16条回答
  • 2020-11-30 17:17

    Here is my program. This is not a perfect solution. There are lots of changes to make in the recursion function. But this end result is perfect. I tried to optimize a bit.

    public class KnightKing2 {
        private static int tempCount = 0;
    
        public static void main(String[] args) throws IOException {
            Scanner in = new Scanner(System.in);
            int ip1 = Integer.parseInt(in.nextLine().trim());
            int ip2 = Integer.parseInt(in.nextLine().trim());
            int ip3 = Integer.parseInt(in.nextLine().trim());
            int ip4 = Integer.parseInt(in.nextLine().trim());
            in.close();
            int output = getStepCount(ip1, ip2, ip3, ip4);
            System.out.println("Shortest Path :" + tempCount);
    
        }
    
        // 2 1 6 5 -> 4
        // 6 6 5 5 -> 2
    
        public static int getStepCount(int input1, int input2, int input3, int input4) {
            return recurse(0, input1, input2, input3, input4);
    
        }
    
        private static int recurse(int count, int tx, int ty, int kx, int ky) {
    
            if (isSolved(tx, ty, kx, ky)) {
                int ccount = count+1;
                System.out.println("COUNT: "+count+"--"+tx+","+ty+","+ccount);
                if((tempCount==0) || (ccount<=tempCount)){
                    tempCount = ccount;
                }
                return ccount;
            }
    
                if ((tempCount==0 || count < tempCount) && ((tx < kx+2) && (ty < ky+2))) {
                    if (!(tx + 2 > 8) && !(ty + 1 > 8)) {
                        rightTop(count, tx, ty, kx, ky);
    
                    }
                    if (!(tx + 2 > 8) && !(ty - 1 < 0)) {
                        rightBottom(count, tx, ty, kx, ky);
                    }
                    if (!(tx + 1 > 8) && !(ty + 2 > 8)) {
                        topRight(count, tx, ty, kx, ky);
                    }
                    if (!(tx - 1 < 0) && !(ty + 2 > 8)) {
                        topLeft(count, tx, ty, kx, ky);
                    }
                    if (!(tx + 1 > 8) && !(ty - 2 < 0)) {
                         bottomRight(count, tx, ty, kx, ky);
                    }
                    if (!(tx - 1 < 0) && !(ty - 2 < 0)) {
                         bottomLeft(count, tx, ty, kx, ky);
                    }
                    if (!(tx - 2 < 0) && !(ty + 1 > 8)) {
                        leftTop(count, tx, ty, kx, ky);
                    }
                    if (!(tx - 2 < 0) && !(ty - 1 < 0)) {
                        leftBottom(count, tx, ty, kx, ky);
                    }
                }
    
            return count;
    
        }
    
        private static int rightTop(int count, int tx, int ty, int kx, int ky) {
            return count + recurse(count + 1, tx + 2, ty + 1, kx, ky);
    
        }
    
        private static int topRight(int count, int tx, int ty, int kx, int ky) {
            return count + recurse(count + 1, tx + 1, ty + 2, kx, ky);
        }
    
        private static int rightBottom(int count, int tx, int ty, int kx, int ky) {
            return count + recurse(count + 1, tx + 2, ty - 1, kx, ky);
        }
    
        private static int bottomRight(int count, int tx, int ty, int kx, int ky) {
            return count + recurse(count + 1, tx + 1, ty - 2, kx, ky);
        }
    
        private static int topLeft(int count, int tx, int ty, int kx, int ky) {
            return count + recurse(count + 1, tx - 1, ty + 2, kx, ky);
        }
    
        private static int bottomLeft(int count, int tx, int ty, int kx, int ky) {
            return count + recurse(count + 1, tx - 1, ty - 2, kx, ky);
        }
    
        private static int leftTop(int count, int tx, int ty, int kx, int ky) {
            return count + recurse(count + 1, tx - 2, ty + 1, kx, ky);
        }
    
        private static int leftBottom(int count, int tx, int ty, int kx, int ky) {
            return count + recurse(count + 1, tx - 2, ty - 1, kx, ky);
        }
    
        private static boolean isSolved(int tx, int ty, int kx, int ky) {
            boolean solved = false;
            if ((tx == kx) && (ty == ky)) {
                solved = true;
            } else if ((tx + 2 == kx) && (ty + 1 == ky)) { // right top
                solved = true;
            } else if ((tx + 2 == kx) && (ty - 1 == ky)) { // right bottom
                solved = true;
            } else if ((ty + 2 == ky) && (tx + 1 == kx)) {// top right
                solved = true;
            } else if ((ty + 2 == ky) && (tx - 1 == kx)) {// top left
                solved = true;
            } else if ((tx - 2 == kx) && (ty + 1 == ky)) { // left top
                solved = true;
            } else if ((tx - 2 == kx) && (ty - 1 == ky)) {// left bottom
                solved = true;
            } else if ((ty - 2 == ky) && (tx + 1 == kx)) { // bottom right
                solved = true;
            } else if ((ty - 2 == ky) && (tx - 1 == kx)) { // bottom left
                solved = true;
            }
    
            return solved;
        }
    
    }
    
    0 讨论(0)
  • 2020-11-30 17:18

    Very interesting problem which I was encountered recently. After looking some solutions I was tried to recover analytic formula (O(1) time and space complexity) given on SACO 2007 Day 1 solutions.

    First of all I want to appreciate Graeme Pyle for very nice visualization which helped me to fix formula.

    For some reason (maybe for simplification or beauty or just a mistake) they moved minus sign into floor operator, as a result they have got wrong formula floor(-a) != -floor(a) for any a.

    Here is the correct analytic formula:

    var delta = x-y;
    if (y > delta) {
        return delta - 2*Math.floor((delta-y)/3);
    } else {
        return delta - 2*Math.floor((delta-y)/4);
    }
    

    The formula works for all (x,y) pairs (after applying axes and diagonal symmetry) except (1,0) and (2,2) corner cases, which are not satisfy to pattern and hardcoded in the following snippet:

    function distance(x,y){
         // axes symmetry 
         x = Math.abs(x);
         y = Math.abs(y);
         // diagonal symmetry 
         if (x < y) {
            t = x;x = y; y = t;
         }
         // 2 corner cases
         if(x==1 && y == 0){
            return 3;
         }
         if(x==2 && y == 2){
            return 4;
         }
        
        // main formula
        var delta = x-y;
    		if(y>delta){
      		return delta - 2*Math.floor((delta-y)/3);
      	}
      	else{
      		return delta - 2*Math.floor((delta-y)/4);
      	}
    }
    
    
    $body = $("body");
    var html = "";
    for (var y = 20; y >= 0; y--){
    	html += '<tr>';
    	for (var x = 0; x <= 20; x++){
      	html += '<td style="width:20px; border: 1px solid #cecece" id="'+x+'_'+y+'">'+distance(x,y)+'</td>';
      }
      html += '</tr>';
    }
    
    html = '<table>'+html+'</table>';
    $body.append(html);
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    Note: The jQuery used for only illustration, for code see distance function.

    0 讨论(0)
  • 2020-11-30 17:19
    public class Horse {
    
        private int[][] board;
        private int[] xer = { 2, 1, -1, -2, -2, -1, 1, 2 };
        private int[] yer = { 1, 2, 2, 1, -1, -2, -2, -1 };
        private final static int A_BIG_NUMBER = 10000;
        private final static int UPPER_BOUND = 64;
    
    
        public Horse() {
            board =  new int[8][8];
        }
    
        private int solution(int x, int y, int destx, int desty, int move) {
    
            if(move == UPPER_BOUND) {
                /* lets put an upper bound to avoid stack overflow */
                return A_BIG_NUMBER;
            }
    
            if(x == 6 && y ==5) {
                board[6][5] = 1;
                return 1;
            }
            int min = A_BIG_NUMBER;
            for (int i = 0 ; i < xer.length; i++) {
                if (isMoveGood(x + xer[i], y + yer[i])) {
                    if(board[x + xer[i]][y + yer[i]] != 0) {
                        min = Integer.min(min, 1 + board[x +xer[i]] [y +yer[i]]);                   
                    } else {
                        min = Integer.min(min, 1 + solution(x + xer[i], y + yer[i], destx, desty, move + 1));   
                    }                   
                }
            }   
            board[x][y] = min;
            return min;
        }
    
    
        private boolean isMoveGood(int x, int y) {
            if (x >= 0 && x < board.length && y >= 0 && y < board.length)
                return true;
            return false;
        }
    
    
        public static void main(String[] args) {
    
            int destX = 6;
            int destY = 7;
            final Horse h = new Horse();
            System.out.println(h.solution(0, 0, destX, destY, 0));
        }
    }
    
    0 讨论(0)
  • 2020-11-30 17:19

    Just ruby code from Graeme Pyle's answer's jsfiddle above, striped all extra code and converted remaining to ruby just to get solution by his algorithm, seems like working. Still testing though:

    def getBoardOffset(board)
      return board.length / 2
    end
    
    def setMoveCount(x, y, count, board)
      offset = getBoardOffset(board)
      board[y + offset][x + offset] = count
    end
    
    def getMoveCount(x, y, board)
        offset = getBoardOffset(board)
        row = board[y + offset]
        return row[x + offset]
    end
    
    def isBottomOfVerticalCase(x, y)
        return (y - 2 * x) % 4 == 0
    end
    
    def isPrimaryDiagonalCase(x, y)
        return (x + y) % 2 == 0
    end
    
    def isSecondaryDiagonalCase(x, y)
        return (x + y) % 2 == 1
    end
    
    def simplifyBySymmetry(x, y)
        x = x.abs
        y = y.abs
        if (y < x)
          t = x
          x = y
          y = t
        end
        return {x: x, y: y}
    end
    
    def getPrimaryDiagonalCaseMoveCount(x, y)
        var diagonalOffset = y + x
        var diagonalIntersect = diagonalOffset / 2
        return ((diagonalIntersect + 2) / 3).floor * 2
    end
    
    def getSpecialCaseMoveCount(x, y)
        specials = [{
                x: 0,
                y: 0,
                d: 0
            },
            {
                x: 0,
                y: 1,
                d: 3
            },
            {
                x: 0,
                y: 2,
                d: 2
            },
            {
                x: 0,
                y: 3,
                d: 3
            },
            {
                x: 2,
                y: 2,
                d: 4
            },
            {
                x: 1,
                y: 1,
                d: 2
            },
            {
                x: 3,
                y: 3,
                d: 2
            }
        ];
        matchingSpecial=nil
        specials.each do |special|
          if (special[:x] == x && special[:y] == y)
            matchingSpecial = special
          end
        end
        if (matchingSpecial)
          return matchingSpecial[:d]
        end
    end
    
    def isVerticalCase(x, y)
      return y >= 2 * x
    end
    
    def getVerticalCaseMoveCount(x, y)
        normalizedHeight = getNormalizedHeightForVerticalGroupCase(x, y)
        groupIndex = (normalizedHeight/4).floor
        groupStartMoveCount = groupIndex * 2 + x
        return groupStartMoveCount + getIndexInVerticalGroup(x, y)
    end
    
    def getIndexInVerticalGroup(x, y)
        return getNormalizedHeightForVerticalGroupCase(x, y) % 4
    end
    
    def getYOffsetForVerticalGroupCase(x) 
        return x * 2
    end
    
    def getNormalizedHeightForVerticalGroupCase(x, y)
        return y - getYOffsetForVerticalGroupCase(x)
    end
    
    def getSecondaryDiagonalCaseMoveCount(x, y)
        diagonalOffset = y + x
        diagonalIntersect = diagonalOffset / 2 - 1
        return ((diagonalIntersect + 2) / 3).floor * 2 + 1
    end
    
    def getMoveCountO1(x, y)
        newXY = simplifyBySymmetry(x, y)
        x = newXY[:x]
        y = newXY[:y]
        specialMoveCount = getSpecialCaseMoveCount(x ,y)
        if (specialMoveCount != nil)
          return specialMoveCount
        elsif (isVerticalCase(x, y))
          return getVerticalCaseMoveCount(x ,y)
        elsif (isPrimaryDiagonalCase(x, y))
          return getPrimaryDiagonalCaseMoveCount(x ,y)
        elsif (isSecondaryDiagonalCase(x, y))
          return getSecondaryDiagonalCaseMoveCount(x ,y)
        end
    end
    
    def solution(x ,y)
      return getMoveCountO1(x, y)
    end
    
    
    puts solution(0,0)
    

    Only intention is to save someone some time converting code if anyone needs full code.

    0 讨论(0)
提交回复
热议问题