zoukankan      html  css  js  c++  java
  • 马周游问题(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了差别很大。

  • 相关阅读:
    datanode报错Problem connecting to server
    使用命令查看hdfs的状态
    Access denied for user root. Superuser privilege is requ
    ElasticSearch默认的分页参数 size
    SparkStreaming Kafka 维护offset
    【容错篇】Spark Streaming的还原药水——Checkpoint
    251 Android 线性与相对布局简介
    250 Android Studio使用指南 总结
    249 如何解决项目导入产生的中文乱码问题
    248 gradle更新问题
  • 原文地址:https://www.cnblogs.com/Jabba93/p/2919843.html
Copyright © 2011-2022 走看看