最近研究算法,看着了一个基础编程题“马踏棋盘”。尝试用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;
}
}