• 马周游问题(Java实现)


    马周游问题

    1. 问题描述

    在一个n*n的棋盘中的某个位置有一只马,如果它走n*n步正好经过除起点外的其他位置各一次,这样一种走法则称马的周游路线,试设计一个算法,从给定的起点出发,找出它的一条周游路线。

    2. 回溯法的一般思路

    对于用回溯法求解的问题,首先要将问题进行适当的转化,得出状态空间树。 这棵树的每条完整路径都代表了一种解的可能。通过深度优先搜索这棵树,枚举每种可能的解的情况;从而得出结果。但是,回溯法中通过构造约束函数,可以大大 提升程序效率,因为在深度优先搜索的过程中,不断的将每个解(并不一定是完整的,事实上这也就是构造约束函数的意义所在)与约束函数进行对照从而删除一些 不可能的解,这样就不必继续把解的剩余部分列出从而节省部分时间。

    3. 求解问题的回溯算法描述

    1.按顺时针方向搜索当前点的8个方向,如果没有走过的就摘取下来。

    2.判断点的个数是否为0,否的继续执行3,为0转5

    3.对摘下来的点进行打分,规制:入度少的为第一优先级,靠边缘的为第二优先级。

    4.根据分数获取分数最少的点(分数少的优先)。转到1

    5.判断栈中的保存的点是否为空,如果为空,退出程序。如果不为空,就退一步,转到1.

    4. 算法实现的关键技巧

    1.判断要走的下一个点还有多少个点可以到达这个点,少的优先。

    2.条件1相同的话,靠边的先走。

    3.不管输入的点是哪一个,都是从中间位置开始,最后通过位移算出从输入那个点的路径。(对于这点,很多人都是不明白,我也不明白那些人为什么不明白,其实是一个很简单的道理。因为你最后走出来的是一个回路,不管那个棋盘是怎样的,最后你肯定可以把它变成一个环,环的每一个结点就是由棋盘中的格子和步数组成,在不移动格子的情况下,对数字进行转圈,然后再按拆开的办法放回去就会发现数字已经移动了)废话多了

    下面贴代码,代码有三部分组成,用的是面向对象的方法

    KnightTourPro类 负责运行程序

    MPoint类 棋盘格子

    ShowInfoWindow类 负责显示运行后的效果

    KinghtTourPro

       1:  package nom.auggie.Knight;
       2:   
       3:  import java.awt.Point;
       4:  import java.util.Scanner;
       5:   
       6:  import nom.auggie.Knight.gui.ShowInfoWindow;
       7:   
       8:  public class KnightTourPro {
       9:   
      10:      static final int NO_PASS = 0;
      11:      /**
      12:       * 代表8个方向,顺时针方向
      13:       */
      14:      private static final Point[] dirs = { new Point(-2, 1), new Point(-1, 2), new Point(1, 2),
      15:              new Point(2, 1), new Point(2, -1), new Point(1, -2), new Point(-1, -2),
      16:              new Point(-2, -1) };
      17:   
      18:      /**
      19:       * 矩阵大小
      20:       */
      21:      private int size;
      22:   
      23:      /**
      24:       * 栈指针
      25:       */
      26:      private int stackL = -1;
      27:   
      28:      /**
      29:       * 记录开始点
      30:       */
      31:      private MPoint oPt = new MPoint();
      32:      /**
      33:       * 当前的步数
      34:       */
      35:      private int step = 1;
      36:   
      37:      /**
      38:       * 点矩阵矩阵
      39:       */
      40:      private MPoint[][] mPath;
      41:   
      42:      /**
      43:       * 当前点的位置
      44:       */
      45:      private MPoint lPoint;
      46:   
      47:      /**
      48:       * 保存走过的点
      49:       */
      50:      private MPoint[] stackPoint;
      51:   
      52:      public KnightTourPro(int size) {
      53:          this.size = size;
      54:          this.mPath = new MPoint[size][size];
      55:          for (int i = 0; i < mPath.length; i++) {
      56:              for (int j = 0; j < mPath.length; j++) {
      57:                  mPath[i][j] = new MPoint(i, j);
      58:                  this.getPSScore(mPath[i][j]);
      59:              }
      60:          }
      61:          this.stackPoint = new MPoint[size * size];
      62:      }
      63:   
      64:      /**
      65:       * 开始执行
      66:       * 
      67:       * @return
      68:       */
      69:      public int[][] doWalk(int x, int y) {
      70:          oPt.x = x;
      71:          oPt.y = y;
      72:          lPoint = new MPoint(x, y);
      73:          stackPoint[++stackL] = this.lPoint;
      74:          mPath[this.lPoint.x][this.lPoint.y].stepNum = step++;
      75:          int i=0;
      76:          do {
      77:              if (!this.goNext()) {
      78:                  if (!this.goBack()) {
      79:                      if(i==0){ this.debugPrint();i++;}
      80:                      break;
      81:                  }
      82:              }
      83:              // debugPrint();
      84:              if (step - 1 == size * size) {
      85:                  if (isComeBack()) break;
      86:              }
      87:          } while (true);
      88:          if (step < 1) return null;
      89:          return this.toIntMatrix();
      90:      }
      91:   
      92:      private boolean isComeBack() {
      93:          // System.out.println("isComeBack");
      94:          int x = stackPoint[stackL].x;
      95:          int y = stackPoint[stackL].y;
      96:          for (int i = 0; i < 8; i++) {
      97:              if ((x + dirs[i].x) == oPt.x && (y + dirs[i].y) == oPt.y) { return true; }
      98:          }
      99:          return false;
     100:      }
     101:   
     102:      /**
     103:       * 调试用的
     104:       */
     105:      private void debugPrint() {
     106:          int[][] mPath = this.toIntMatrix();
     107:          for (int[] i : mPath) {
     108:              for (int j : i) {
     109:                  System.out.print(j + " ");
     110:              }
     111:              System.out.println();
     112:          }
     113:          System.out.println();
     114:          // try {
     115:          // Thread.sleep(1000);
     116:          // } catch (InterruptedException e) {
     117:          // // TODO Auto-generated catch block
     118:          // e.printStackTrace();
     119:          // }
     120:      }
     121:   
     122:      private int[][] toIntMatrix() {
     123:          int[][] matrix = new int[size][size];
     124:          for (int i = 0; i < size; i++) {
     125:              for (int j = 0; j < size; j++) {
     126:                  matrix[i][j] = this.mPath[i][j].stepNum;
     127:              }
     128:          }
     129:          return matrix;
     130:      }
     131:   
     132:      /**
     133:       * 回退函数
     134:       * @return
     135:       */
     136:      private boolean goBack() {
     137:          if (this.stackL > 0) {
     138:              stackPoint[stackL].stepNum = NO_PASS;// 设置这个点没有走过
     139:              stackPoint[stackL].cleanDirsState();// 设置路径没有走过
     140:              this.lPoint = this.stackPoint[--stackL];// 退栈
     141:              step--;
     142:              return true;
     143:          }
     144:          return false;
     145:      }
     146:   
     147:      /**
     148:       * 获得下个最佳的点
     149:       * 
     150:       * @param lPoint
     151:       *            当前的点
     152:       * @return
     153:       */
     154:      public boolean goNext() {
     155:          MPoint[] ptsCanGo = new MPoint[8];// 临时存储那个方向可以去的点的序号
     156:          // 保存方向的位置
     157:          int j = 0;
     158:          for (int i = 0; i < 8; i++) {
     159:              if (isCanGo(lPoint, dirs[i])) {
     160:                  ptsCanGo[j] = mPath[lPoint.x + dirs[i].x][lPoint.y + dirs[i].y];// 获得可以走的点
     161:                  ptsCanGo[j].dirIndex = i;// 记录方向序号
     162:                  j++;
     163:              }
     164:          }
     165:          if (j == 0) return false;// 没有下一个点,向前走失败
     166:          int i = 0;
     167:          if (ptsCanGo[i].equals(stackPoint[stackL])) i++;// 防止第一个为来点
     168:          if (i > j) return false;// 表示唯一一个可以走的点为来点
     169:          MPoint[] pts = new MPoint[8];
     170:          // 判断点是否已经走过,没有走过的点保存在pts中
     171:          int n = 0;
     172:          int k = 0;
     173:          for (k = 0; k < j; k++) {
     174:              // 如果这个方向没有走过,并且你是来自这个方向的话
     175:              if (!lPoint.dirs[ptsCanGo[k].dirIndex]) {
     176:                  pts[n] = ptsCanGo[k];
     177:                  this.getPScore(pts[n]);// 给点打分
     178:                  n++;
     179:              }
     180:          }
     181:          if (n == 0) return false;// 所有点都走过了
     182:          MPoint mVPoint = pts[0];
     183:          for (int m = 1; m < n; m++) {
     184:              if (mVPoint.compareWithValue(pts[m]) == -1) {
     185:                  mVPoint = pts[m];
     186:              }
     187:          }
     188:          this.lPoint.dirs[mVPoint.dirIndex] = true;// 设置为已走过
     189:          this.lPoint = mVPoint;
     190:          lPoint.stepNum = step++;// 把步数存入点中
     191:          stackPoint[++stackL] = lPoint;// 已走过,压入栈中
     192:          return true;
     193:      }
     194:   
     195:      /**
     196:       * 给结点动态打分
     197:       * 
     198:       * @param mp
     199:       */
     200:      public void getPScore(MPoint mp) {
     201:          mp.firstValue =8;
     202:          mp.firstValue = this.canGoCount(mp);
     203:      }
     204:   
     205:      /**
     206:       * 给结点静态打分,某个结点分配下来就是静态的分数不会变的
     207:       * 
     208:       * @param mp
     209:       *            要打分的点
     210:       */
     211:   
     212:      public void getPSScore(MPoint mp) {
     213:          mp.seconedValue = Integer.MAX_VALUE;
     214:          
     215:          int lengthHalf = mPath.length / 2;
     216:          if (mp.x <= lengthHalf / 2) {
     217:              mp.seconedValue += mp.x;
     218:          } else {
     219:              mp.seconedValue += (mPath.length-mp.x);
     220:          }
     221:          if (mp.y <= lengthHalf / 2) {
     222:              mp.seconedValue += mp.y;
     223:          } else {
     224:              mp.seconedValue += (mPath.length-mp.y);
     225:          }
     226:  //        System.out.println(mp.seconedValue);
     227:      }
     228:   
     229:      /**
     230:       * 获得结点的出度
     231:       * 
     232:       * @param mp
     233:       *            结点
     234:       * @return
     235:       */
     236:      public int canGoCount(MPoint mp) {
     237:          int count = 0;
     238:          for (int i = 0; i < dirs.length; i++) {
     239:              if (isCanGo(mp, dirs[i])) {
     240:                  count++;
     241:              }
     242:          }
     243:          return count;
     244:      }
     245:   
     246:      /**
     247:       * 判断是否可以过去
     248:       * 
     249:       * @param mp
     250:       *            要判断的起点
     251:       * @param dir
     252:       *            代表方向的点
     253:       * @return
     254:       */
     255:      public boolean isCanGo(MPoint mp, Point dir) {
     256:          int x = mp.x + dir.x;
     257:          int y = mp.y + dir.y;
     258:          if (x < size && x >= 0 && y < size && y >= 0
     259:                  && mPath[x][y].stepNum == KnightTourPro.NO_PASS) { return true; }
     260:          return false;
     261:      }
     262:   
     263:      public static void main(String[] args) {
     264:          
     265:          
     266:          while (true) {
     267:              Scanner scan = new Scanner(System.in);
     268:              System.out.print("输入矩阵大小");
     269:              int size = scan.nextInt();
     270:              System.out.print("输入开始点\nx=");
     271:              int x = scan.nextInt();
     272:              System.out.print("y=");
     273:              int y = scan.nextInt();
     274:              KnightTourPro knight = new KnightTourPro(size);
     275:              final int[][] mPath = knight.doWalk(x - 1, y - 1);
     276:              if (mPath == null) {
     277:                  System.out.println("无解");
     278:              }
     279:              for (int[] i : mPath) {
     280:                  for (int j : i) {
     281:                      System.out.print(j + " ");
     282:                  }
     283:                  System.out.println();
     284:              }
     285:              new Thread(){
     286:                  @Override
     287:                  public void run(){
     288:                      ShowInfoWindow show = new ShowInfoWindow(mPath);
     289:                      show.setVisible(true);
     290:                      show.startAnimation();
     291:                  }
     292:              }.start();
     293:          }
     294:          
     295:   
     296:      }
     297:  }

    MPoint

       1:  package nom.auggie.Knight;
       2:   
       3:  public class MPoint {
       4:   
       5:      /**
       6:       * 过来对应方向的序号
       7:       */
       8:      public int dirIndex = -1;
       9:      /**
      10:       * 对应点的步数
      11:       */
      12:      public int stepNum = 0;
      13:      /**
      14:       * 棋盘坐标x
      15:       */
      16:      public int x;
      17:   
      18:      /**
      19:       * 棋盘坐标y
      20:       */
      21:      public int y;
      22:   
      23:      /**
      24:       * 点的第一价值价值
      25:       */
      26:      public int firstValue=8;
      27:   
      28:      /**
      29:       * 第二价值
      30:       */
      31:      public int seconedValue=Integer.MAX_VALUE;
      32:   
      33:      /**
      34:       * 点的8个方向,顺时针数,走过的就设置为true;
      35:       */
      36:      public boolean[] dirs = new boolean[8];
      37:   
      38:      public MPoint puls(MPoint mPoint) {
      39:          return new MPoint(this.x + mPoint.x, this.y + mPoint.y);
      40:      }
      41:   
      42:      /**
      43:       * 比较价值,第一价值优先,
      44:       * 
      45:       * @param p
      46:       * @return 1 比p价值大,-1 比p价值小,0 价值相同
      47:       */
      48:      public int compareWithValue(MPoint p) {
      49:          if (p == null) return -1;
      50:          if (this.firstValue < p.firstValue) return 1;
      51:          if (this.firstValue == p.firstValue) {
      52:              if (this.seconedValue == p.seconedValue) return 0;
      53:              return this.seconedValue < p.seconedValue ? 1 : -1;
      54:          }
      55:          return -1;
      56:      }
      57:   
      58:      public void cleanDirsState() {
      59:          for (int i = 0; i < dirs.length; i++) {
      60:              dirs[i] = false;
      61:          }
      62:      }
      63:   
      64:      public MPoint(int x, int y, int fristValue, int seconedValue) {
      65:          this.x = x;
      66:          this.y = y;
      67:          this.firstValue = fristValue;
      68:          this.seconedValue = seconedValue;
      69:      }
      70:   
      71:      public MPoint() {
      72:      }
      73:   
      74:      public MPoint(int x, int y) {
      75:          this.x = x;
      76:          this.y = y;
      77:      }
      78:   
      79:      public MPoint(MPoint p) {
      80:          x = p.x;
      81:          y = p.y;
      82:          firstValue = p.firstValue;
      83:          seconedValue = p.seconedValue;
      84:      }
      85:   
      86:      /**
      87:       * 设定点的坐标
      88:       * 
      89:       * @param p
      90:       */
      91:      public void setMPoint(MPoint p) {
      92:          this.x = p.x;
      93:          this.y = p.y;
      94:      }
      95:   
      96:      @Override
      97:      public boolean equals(Object obj) {
      98:          if (obj == null) return false;
      99:          if (obj instanceof MPoint) {
     100:              MPoint mp = (MPoint) obj;
     101:              if (mp.x == this.x && mp.y == this.y) return true;
     102:          }
     103:          return false;
     104:      }
     105:  }

    ShowInfoWindow

       1:  package nom.auggie.Knight.gui;
       2:   
       3:  import java.awt.Color;
       4:   
       5:  public class ShowInfoWindow extends JFrame {
       6:   
       7:      public static final int FREQUENCY = 2;
       8:      public static final int DELAY_TIME=50;
       9:      private Point[] pts;
      10:      private int[][] matrix;
      11:      private JPanel contentPane;
      12:      private JLabel[][] jLabels;
      13:      int[][] in = new int[50][50];
      14:      
      15:      /**
      16:       * Create the frame.
      17:       */
      18:  //    public ShowInfoWindow() {
      19:      public ShowInfoWindow(int[][] matrix) {
      20:          this.matrix = matrix;
      21:          setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      22:          setBounds(100, 0, 1024, 768);
      23:          contentPane = new JPanel();
      24:          contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
      25:          setContentPane(contentPane);
      26:          GridLayout gLayout = new GridLayout(matrix.length,matrix.length);
      27:          int padding = 3;
      28:          gLayout.setHgap(padding);
      29:          gLayout.setVgap(padding);
      30:          contentPane.setLayout(gLayout);
      31:          jLabels = new JLabel[matrix.length][matrix.length];
      32:          for(int i=0;i<jLabels.length;i++){
      33:              for(int j=0;j<jLabels[i].length;j++){
      34:                  jLabels[i][j] = new JLabel();
      35:                  jLabels[i][j].setHorizontalAlignment(SwingConstants.CENTER);
      36:                  jLabels[i][j].setOpaque(true);
      37:                  contentPane.add(jLabels[i][j]);
      38:              }
      39:          }
      40:          pts = new Point[matrix.length*matrix.length];
      41:          this.analyseMatrix();
      42:      }
      43:      
      44:   
      45:      public void startAnimation(){
      46:          for(int i=0;i<pts.length;i++){
      47:              this.labelAnim(pts[i].x, pts[i].y);
      48:          }
      49:      }
      50:      
      51:   
      52:   
      53:      /**
      54:       * 渲染label
      55:       * @param indexX 对应的横坐标
      56:       * @param indexY 纵坐标
      57:       */
      58:      public void labelAnim(int indexX,int indexY){
      59:          JLabel aLab = jLabels[indexX][indexY];
      60:          aLab.setText(matrix[indexX][indexY]+"");
      61:          for(int i=0;i<FREQUENCY;i++){
      62:              aLab.setBackground(Color.BLUE);
      63:              aLab.updateUI();
      64:              try {
      65:                  Thread.sleep(DELAY_TIME);
      66:              } catch (InterruptedException e) {
      67:                  // TODO Auto-generated catch block
      68:                  e.printStackTrace();
      69:              }
      70:              aLab.setBackground(Color.red);
      71:              try {
      72:                  Thread.sleep(DELAY_TIME);
      73:              } catch (InterruptedException e) {
      74:                  // TODO Auto-generated catch block
      75:                  e.printStackTrace();
      76:              }
      77:          }
      78:      }
      79:      
      80:      /**
      81:       * 分析矩阵
      82:       */
      83:      public void analyseMatrix(){
      84:          for(int i=0;i<matrix.length;i++){
      85:              for(int j=0;j<matrix.length;j++){
      86:                  pts[matrix[i][j]-1] = new Point(i,j);
      87:              }
      88:          }
      89:      }
      90:   
      91:  }

    运行效果图(8*8)

    image

    1. 自我评价及心得体会

    程序实现的还不够好,理论上使用的启发式搜索的话应该可以跑到3000*3000的但是现在还只是能跑到26*26,和理论差太远了。还需努力。

    心得体会:不用启发式的最多这是能搜到8*8而已,使用启发式立刻到26*26了差别很大。

  • 相关阅读:
    第一次冲次(补)
    软件工程概论个人总结
    第16周进度条
    读《梦断代码》第2章有感
    java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver
    传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确。参数 1 (""): 数据类型 0x38 未知。
    怎么卸载VS2005呢?控制面板里内容太多,找不出哪些是属于VS2005?我的VS2005出问题了
    常用正则表达式的写法
    Http响应头字段详解,MyEclipse配置tomcat,servlet运行方式
    html框架 字体颜色 列表 表格 图片 定义列表 a标签
  • 原文地址:https://www.cnblogs.com/Jabba93/p/2919843.html
Copyright © 2020-2023  润新知