马踏棋盘问题解决-利用深度搜索和贪婪算法优化

最近研究算法,看着了一个基础编程题“马踏棋盘”。尝试用java来解决一下,代码有参考

package com.zjt.wuling.depsearch;


/**
 * 关于‘马踏棋盘’问题,利用‘贪婪算法’优化的学习及尝试
 * @since 2015年6月18日 上午11:10:23
 * @author wuling
 */
public class HorseGreedyLearn {

    /**
     * 解决问题思路:
     * 1. 依然是以深度搜索算法(及利用递归算法)来解决问题
     * 2. 在每一次探索‘跳马’的下一步时,根据‘贪婪算法’的原则,选择‘再次跳马’时可选择最少的那一种‘跳马’。这里需要存放每一个可能的下一点(有‘再次跳马’可能的)所有可能的选择性
     * 3. 在接近完成时,可能出现没有符合规则的下一步‘跳马’的选择, 则选择‘回溯’;在‘回溯’的上一点时,选择‘次优’()方案,继续向下走。
     * 4. 在要求求得多种解决方案时,如何将再次的方案和之前成功的方案判断不一致???
     * ->应该是在某一方案成功之后, 重新回溯,用一个数组保存方案的所有点及步骤数。更改前做对比;??多种方式时??
     */
    
    //8*8的棋盘
   static int staticNum = 8;
    
    //保存多个解决方案: 一层数组-方案排序; 二层数组+三层数组-‘跳马’的坐标位置
    //即保存50个方案《=》位置及‘第几步’集合 ---->用于结果的打印输出
    static int multiCount = 50;
    static int[][][] multiSolution  = new int [multiCount][staticNum][staticNum];
    
    static int tmpMultiCountRecord = 0;//记录当前正在获取第几个解决方案 ;即计算当前算出了多少种解法
    
    //表示深度搜索时的深度; 当dep=64时,一个‘跳马’的方案完成。
   static  int dep = 1;//
    
    //‘跳马’可选择‘点’的x坐标‘相对位置’集合
  static  int[] fx = {-2, -1, 1, 2,  2,  1, -1, -2};
    //‘跳马’可选择‘点’的y坐标‘相对位置’集合
    static int[] fy = { 1, 2,  2, 1, -1, -2, -2, -1};
    
    //stepDiffList表示一维的,给数组stepList用; 与fx、fy对应
    static int[] stepDiffList = {-15, -6, 10, 17, 15, 6, -10, -17};
    
    /**
     * []用一维数组记录8*8棋盘中马的遍历路径=>eg:第1步的坐标为1,2->则stepList[1*8+2]=1; 在打印时
     * for(i = 0;i < 8;i++)
     *      for(j = 0;j < 8;j++)
     *          out[z][i][j] = stepList[i*8+j];
     * 然后可以输出        
     */
    static int[] stepList = new int[staticNum*staticNum];
    
    /**
     * 
     * @param args
     * @author wuling
     */
    public static void main(String[] args) {
        
            int orNum = init(2,1);
            
            search(orNum);
            
            print();
    }
    
    
    
    
    public static void print() {
        
        int i,j,k;
        System.out.println("展示详细遍历=====:");
            for(i = 0;i < multiCount;i++)
            {
                System.out.println("第"+(i+1)+"个解: ");
                for(j = 0;j < 8;j++)
                {
                    for(k = 0;k < 8;k++)
                        System.out.printf("%3d",multiSolution[i][j][k]);
                    System.out.println();
                }
            }
//        }
        
    }




    /**
     * 初始化
     * @param initX 初始化点坐标的X轴值
     * @param initY 初始化点坐标的Y轴值
     * @return
     * @author wuling
     */
    public static int init(int initX, int initY){
        //初始化
        for(int i = 0 ;i < stepList.length; i++){
            stepList[i] = 0;
        }
        int originNum = initX*staticNum + initY;
        stepList[originNum] = 1;
        return originNum;
    }
    
    /**
     * 开始逻辑处理
     * @param originNum 初始点的数字化后值
     * @author wuling
     */
    public static void search(int originNum){
        //用于‘贪婪算法’,在‘每一步’选择最优解时, 做为临时存储的步骤集合
        int[][] tmpStepStorage = new int[64][8];
         
        sorting(tmpStepStorage, originNum, -1);
        
        int[] tmpStepNum = new int[64];
        tmpStepNum[0] = originNum;
        
        int actNext ;
        while(dep >= 0 ){//作为判断条件
            //有可供‘跳马’的点;即存在可跳的下一点。 
            //另: 在某一方案最后完成的时候,如果打算获取多个方案时,会重新向上溯源....
            if(tmpStepStorage[originNum][0]  != -1){
                //值为0-7; 即当前‘点’实际选择跳的‘下一点’
                actNext = tmpStepStorage[originNum][ tmpStepStorage[originNum][0] ];
                if(-1 != actNext){
                    //*****这个很关键==决定=》在‘回溯’的上一点时,选择‘次优’()方案,继续向下走
                    tmpStepStorage[originNum][0]++;
                    
                    //下一步是【再次‘跳马’可选最少】的一个,
                    originNum += stepDiffList[actNext];
                  
                    stepList[originNum] = ++dep;
                    
                    sorting(tmpStepStorage,originNum,actNext);
                    
                    tmpStepNum[dep-1] = originNum;
                    
                    if(dep == 64)
                    {
                        for(int i = 0 ; i < 8 ;i++)
                            for(int j = 0 ; j< 8;j++)
                                multiSolution[tmpMultiCountRecord][i][j] = stepList[i*8+j];
                        
                        tmpMultiCountRecord++;
                        
                        //结束while循环; 结束程序
                        if(tmpMultiCountRecord == multiCount){
                            System.out.println("完成!");
                            break;
                        }
                    }
                }else{
                    dep--;
                    stepList[originNum] = 0;
                    originNum = tmpStepNum[dep-1];
                }
            }else{//回溯???
                dep--;
                stepList[originNum] = 0;
                originNum = tmpStepNum[dep-1];
            }
        }
    }
    
    //数组为可选的下一步集合,值为‘下一步的再次跳马’的次数;
   static int[] tmpNextSteps = new int[8];
    
    /**
     * 对当前点的‘下一步’选择进行排序,确保将最优解的‘下一步’排序在前
     * @param originNum
     * @author wuling
     */
    public static void sorting (int[][]tmpStepStorage,int originNum, int actPrePoint){
        
        if (actPrePoint != -1) actPrePoint = (actPrePoint + 8 - 4) % 8;
        
        int nextX, nextY;
        int nextNextX, nextNextY;
        for(int i = 0 ;i < staticNum ; i++){
            tmpNextSteps[i] = -1;
            nextX = originNum/staticNum +fx[i];
            nextY = originNum % staticNum + fy[i];
            if(actPrePoint!= i && check(nextX,nextY)){
                tmpNextSteps[i]++;
                //判断该点下一次选择时,有多少个可选的点
                for(int j = 0 ; j < staticNum ; j++){
                    nextNextX = nextX + fx[j];
                    nextNextY = nextY + fy[j];
                    if(check(nextNextX, nextNextY))tmpNextSteps[i]++;
                }
            }
        }
        
        //默认设置:没有可供选择的下一步
        tmpStepStorage[originNum][0] = -1;
        
        int  noableSteps;
        int tmpSteps = 0 ;
        int secondOrigi = 1;
        //将‘下一步’的集合,按最优解排序
        for(int i = 0 ; i < staticNum  ; i++){
               noableSteps = 9;
            for(int j = 0 ; j < staticNum ; j++){
            //下一个点的可选择再次‘跳马’的方案数大于-1 并且 选择最小次数的那个‘下一个点’
                if(tmpNextSteps[j] > -1 && tmpNextSteps[j] < noableSteps){//
                    noableSteps = tmpNextSteps[j];
                    tmpSteps = j;
                }
            }
            if(noableSteps < 9){//
               tmpStepStorage[originNum][secondOrigi++] = tmpSteps;
               tmpNextSteps[tmpSteps] = -1;
               tmpStepStorage[originNum][0] = 1;
           }else{//没有可供选择‘下一步’
               tmpStepStorage[originNum][secondOrigi++] = -1;
               break;
           }
        }
    }
    
    //判断该点是否在范围内且未
    private static boolean check(int xNum, int yNum){
        return xNum >= 0 && yNum >=0 && xNum < 8 && yNum < 8 && stepList[xNum*8 + yNum] == 0;
    }
    
}

    原文作者:骑士周游问题
    原文地址: https://blog.csdn.net/jiubugeinifo/article/details/46562931
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞