AIX 程序设计大赛-AIX正方形问题算法及Java程序实现(方案二)

来源:互联网 发布:中国转运知乎 编辑:程序博客网 时间:2024/05/16 11:45
 
今天又对前天所实现的《AIX 程序设计大赛-AIX正方形问题》解决方案进行了改善,同时又找到了一条崭新的解决方案,没想到效果比想象中的要好,这一篇描述改良方案的算法思路及实现,下一篇介绍一个新的思路更简洁的方案。
 
为了文章的完整性,本篇仍然包括问题描述部分。
 
问题描述:
任意给定一个正方形,将正方形的各边做n等分,并将相应各点连接成水平或垂直的直线,如果从正方形的左下角(0,0)出发,沿各边线或连接线,自左向右或自下而上的方向,到达正方形的右上角(n,n),请用JAVA程序计算并输出所有可能的路径总数和具体线路.请提供相关JAVA源程序和n=2,3,4时的输出结果。输出结果按以下方式:
 
以n=1为例:
n = 1
Path1: (0,0) - (0,1) - (1,1)
Path2: (0,0) - (1,0) - (1,1)
Total = 2
 
解决思路:
上篇回顾
上一篇文章中的解决思路,为通过采用“向上优先”策略,发现通过上一条路径可以直接推导出下一条路径,在这个推导过程中,定义了两个关键点,一个命名为上一条路径的“顶极点”,一个命名为下一条路径的“突破点”,并发现这两个点之间的关系:
 
第一种:若顶极点为上边点,则按照向上优先策略,突破点和顶极点关系为:
breakPoint.x = tipPolePoint.x+1
breakPoint.y = tipPolePoint.y-1
 
第二种:若顶极点为右边点,则按照向上优先策略,突破点和顶极点关系为:
breakPoint.x = (min(x)|y=tipPolePoint.y)+1
breakPoint.y = tipPolePoint.y-1
 
思路优化
通过进一步的分析,发现以上描述的突破点和顶极点的两种关系,最核心的其实是“最后右拐点”,通过最后右拐点我们既可以简化(上一条路径)顶极点的查找,又可以简化(下一条路径)突破点的推导。
最后右拐点定义:既一条路径中最有一次向右拐弯的那个点。
 
依然按照向上优先侧略,下一条路径的突破点和上一条路径的最后右拐点,之间的关系为:
设:最后右拐点为lastRightTurnPoint,突破点为breakPoint。则有
breakPoint.x = lastRightTurnPoint.x+1
breakPoint.y = lastRightTurnPoint.y-1
 
算法特点
由于该算法统一了第一种算法中突破点推导的两种方法,简化了推导过程,所以思路更加清晰、效率更加高效。
 
程序设计:
和以上算法设计类似,这个算法的实现也包括三个类,分别简述如下:
Point:基础类,表示坐标点,和第一方案相同;
AixUtil2:工具类,按照向上优先策略,提供解决AIX正方形问题的一些静态方法,是第一方案的优化;
AixClient:一个简单的调用类,可同时测试方案一(调用AixUtil)和方案二(调用AixUtil2)。
 
源程序代码如下:
Point:基础类,表示坐标点;
 
package qinysong.aix;

/**
 * <p>Title: 基础类,表示坐标点</p>
 * <p>Description: AIX 程序设计大赛---AIX正方形问题</p>
 * <p>Copyright: Copyright (c) 2006</p>
 * <p>Company: qinysong</p>
 * 
@author zhaoqingsong
 * 
@version 1.0 $Date: 2006/09/05 21:44:36 $
 
*/

public class Point {
  
protected int x;
  
protected int y;

  
/**
   * 构造函数
   * 
@param x int
   * 
@param y int
   
*/
  
public Point(int x, int y){
    
this.x = x;
    
this.y = y;
  }

  
public String toString(){
    
return "(" + x + "," + y + ")";
  }

  
/**
   * 判断是否为上边点
   * 
@return boolean
   
*/
  
public boolean isTopBorderPoint(int nValue){
    
return this.y == nValue;
  }

  
/**
   * 判断thePoint是否与自己相等
   * 
@param thePoint Point
   * 
@return boolean
   
*/
  
public boolean equals(Point thePoint){
    
return (this.x == thePoint.x) && (this.y == thePoint.y);
  }

}
 
AixUtil2:工具类,按照向上优先策略,提供解决AIX正方形问题的一些静态方法,是第一方案的优化
 
package qinysong.aix;

/**
 * <p>Title: 工具类,按照向上优先策略,提供解决AIX正方形问题的一些静态方法</p>
 * <p>Description: AIX 程序设计大赛---AIX正方形问题</p>
 * <p>Copyright: Copyright (c) 2006</p>
 * <p>Company: qinysong</p>
 * 
@author zhaoqingsong
 * 
@version 1.0 $Date: 2006/09/05 21:52:18 $
 
*/

public class AixUtil2 {

  
private static int nValue;
  
private static int laseRightTurnIndex;
  
private static Point[] squarePoints= null;

  
/**
   * 初始化正方形边长
   * 
@param nValue int
   
*/
  
public static void initNValue(int nValue) {
    
if (nValue <= 0) {
      
throw new RuntimeException("初始化正方形边长异常,长度不能小于等于零");
    }
    AixUtil2.nValue 
= nValue;
    squarePoints 
= new Point[(nValue+1)*(nValue+1)];
    
for (int y = 0; y <= nValue; y++){
      
for (int x = 0; x <= nValue; x++){
        squarePoints[y
*(nValue+1)+x] = new Point(x,y);
      }
    }
  }

  
/**
   * <p>取得上一条路径的最后右拐点</p>
   * <p>最后右拐点:在到达最后顶点point(n,n)之前的最后一个向右拐的点<br>
   *
   * 
@param previousPathPoints Point[] 上一条路径节点数组
   * 
@return Point  tipPolePoint顶极点
   
*/
  
public static Point getLastRightTurnPoint(Point[] previousPathPoints) {
    Point lastRightTurnPoint 
= null;
    
int index = 2*nValue;
    
while (previousPathPoints[index].x == nValue
           
|| previousPathPoints[index].y == previousPathPoints[index-1].y){
      index
--;
    }
    laseRightTurnIndex 
= index;
    lastRightTurnPoint 
= previousPathPoints[index];
    
return lastRightTurnPoint;
  }

  
/**
   * <p>取得下一条路径的突破点,返回的突破点定义为breakPoint<br>
   * 通过几何数学分析,按照向上优先策略,有如下突破点和上一条路径的最后右拐点的关系<br>
   * breakPoint.x = lastRightTurnPoint.x+1<br>
   * breakPoint.y = lastRightTurnPoint.y-1</p>
   *
   * 
@param lastRightTurnPoint Point 最后右拐点,表示上一条路径的最后右拐点
   * 
@return Point 返回下一条路径的突破点 breakPoint
   
*/
  
public static Point getBreakPoint(Point lastRightTurnPoint) {
    
int index = (lastRightTurnPoint.y - 1)*(nValue+1)+lastRightTurnPoint.x + 1;
    Point breakPoint 
= squarePoints[index];
    
return breakPoint;
  }

  
/**
   * 按照向上优先策略(即能往上走就往上走),取得下一个路径节点
   * 
@param currentPoint Point
   * 
@return Point 下一个路径节点
   
*/
  
public static Point getNextPoint(Point currentPoint) {
    
int index = 0;
    
if (currentPoint.y < nValue) {
      index 
= (currentPoint.y + 1)*(nValue+1)+currentPoint.x;
    } 
else if (currentPoint.x < nValue) {
      index 
= (currentPoint.y)*(nValue+1)+currentPoint.x + 1;
    } 
else {
      
return null;
    }
    
return squarePoints[index];
  }

  
/**
   * 按照向上优先策略(即能往上走就往上走),取得下一条路径节点
   * 
@param previousPathPoints Point[] 上一条路径节点
   * 
@return Point[] 下一条路径
   
*/
  
public static Point[] getNextPath(Point[] previousPathPoints) {
    
int arrayLength = 2*nValue+1;
    Point lastRightTurnPoint 
= getLastRightTurnPoint(previousPathPoints);
    Point breakPoint 
= getBreakPoint(lastRightTurnPoint);
    Point[] nextPath 
= new Point[arrayLength];
    
int index = 0;
    
for (; index < laseRightTurnIndex; index++) {
      nextPath[index] 
= previousPathPoints[index];
    }
    nextPath[index
++= breakPoint;
    Point tempPoint 
= breakPoint;
    
while ( (tempPoint = getNextPoint(tempPoint)) != null) {
      nextPath[index
++= tempPoint;
    }
    
return nextPath;
  }

  
/**
   * 按照向上优先策略,取得第一条路径
   * 
@return Point[]
   
*/
  
public static Point[] getFirstPath() {
    Point[] firstPath 
= new Point[2*nValue+1];
    
for (int i = 0; i <= nValue; i++) {
      firstPath[i] 
= squarePoints[i*(nValue+1)];
    }
    
for (int i = 1; i <= nValue; i++) {
      firstPath[nValue 
+ i] = squarePoints[nValue*(nValue+1)+i];
    }
    
return firstPath;
  }

  
/**
   * <p>按照向上优先策略(即能往上走就往上走),取得下一条路径节点<br>
   * 这个函数是上面getNextPath和getFirstPath的合并,用以得到整体的下一条路径<br>
   * 如果previousPathPoints 为空,则取得第一条路径<br>
   * 如果previousPathPoints不为空,则根据其取得下一条路径</p>
   * 
@param previousPathPoints Point[] 上一条路径节点
   * 
@return Point[] 下一条路径
   
*/
  
public static Point[] getTotalNextPath(Point[] previousPathPoints) {
    
if (previousPathPoints == null){
      
return getFirstPath();
    } 
else {
      
return getNextPath(previousPathPoints);
    }
  }

  
/**
   * 判断是否是最后一条路径
   * 
@param pathPoints Point[]
   * 
@return boolean
   
*/
  
public static boolean isLastPath(Point[] pathPoints){
    
int middleIndex = nValue;
    
return pathPoints[middleIndex].y == 0;
  }

  
/**
   * 按照题目要求格式打印一条路径的节点
   * 
@param pathNumber int
   * 
@param pathPoints Point[]
   
*/
  
public static void printlnPathPoints(int pathNumber, Point[] pathPoints) {
    StringBuffer pathStringBuffer 
= new StringBuffer();
    pathStringBuffer.append(
"Path" + pathNumber + "");
    
int arrayLength = 2*nValue+1;
    
for (int i = 0; i < arrayLength; i++) {
      pathStringBuffer.append(pathPoints[i].toString() 
+ "-");
    }
    String pathString 
= pathStringBuffer.toString();
    
if (pathString.length()>0) pathString = pathString.substring(0,pathString.length()-1);
    System.out.println(pathString);
  }

}
 
AixClient:一个简单的调用类,可同时测试方案一(调用AixUtil)和方案二(调用AixUtil2)
 
package qinysong.aix;

import java.util.Date;

/**
 * <p>Title: 调用类,该类通过工具类AixUtil提供的方法,遍历一个正方形的路径</p>
 * <p>Description: AIX 程序设计大赛---AIX正方形问题</p>
 * <p>Copyright: Copyright (c) 2006</p>
 * <p>Company: qinysong</p>
 * 
@author zhaoqingsong
 * 
@version 1.0 $Date: 2006/09/05 22:49:22 $
 
*/

public class AixClient {

  
public static void main(String[] args) {
    System.out.println(
"AixClient.main begin ......");
    System.out.println(
"AixClient.main 方案1");
    Date beginTime1 
= new Date();
    System.out.println(
"beginTime1:" + beginTime1.toString());
    
int nValue = 5;
    Point[] pathPoints 
= null;
    
int pathNumber = 0;
    System.out.println(
"当n=" + nValue);
    AixUtil.initNValue(nValue);
    
do {
      pathPoints 
= AixUtil.getTotalNextPath(pathPoints);
      
++pathNumber;
      AixUtil.printlnPathPoints(pathNumber, pathPoints);
    }
while (!AixUtil.isLastPath(pathPoints));
    System.out.println(
"Total:" + pathNumber);
    Date endTime1 
= new Date();
    System.out.println(
"end endTime1 :  " + endTime1.toString());


    System.out.println(
"AixClient.main 方案2");
    Date beginTime2 
= new Date();
    System.out.println(
"beginTime2:" + beginTime2.toString());
    System.out.println(
"当n=" + nValue);
    AixUtil2.initNValue(nValue);
    pathPoints 
= null;
    pathNumber 
= 0;
    
do {
      pathPoints 
= AixUtil2.getTotalNextPath(pathPoints);
      
++pathNumber;
      AixUtil2.printlnPathPoints(pathNumber, pathPoints);
    }
while (!AixUtil2.isLastPath(pathPoints));
    System.out.println(
"Total:" + pathNumber);
    Date endTime2 
= new Date();
    System.out.println(
"end endTime2 :  " + endTime2.toString());
    System.out.println(
"方案1所花时间毫秒:  " + (endTime1.getTime() - beginTime1.getTime()));
    System.out.println(
"方案2所花时间毫秒:  " + (endTime2.getTime() - beginTime2.getTime()));

    System.out.println(
"AixClient.main end   ......");
  }
}
 
 
 
原创粉丝点击