AIX 程序设计大赛---AIX正方形问题

本文介绍了一个经典的算法问题“AIX正方形问题”的求解方法。通过使用Java编程语言,设计了三个类来实现该问题的求解,包括点类AixPoint、正方形类AixSquare和客户调用类AixContest。文章详细描述了算法的设计思路、实现细节,并给出了n等于2、3时的具体输出结果。
2006年08月23日 13:13:00

AIX 程序设计大赛---AIX正方形问题

作者:成晓旭

作为"算法及实现"栏目的"抛砖引玉"之作,将自己2年多前实现的一个算法放出来。有一年IBM出了这个Java程序设计竞赛题,当时,自己花晚上时间用Java实现了。

[问题描述]:

任意给定一个正方形,将正方形的各边做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

[设计简介]

共设计3个类:

AixPoint:正方形问题的低层处理类,抽象正方形问题的每个访问点信息;

AixSquare:正方形问题的核心处理类,抽象正方形算法处理过程;

AixContest:正方形问题的客户调用处理类,抽象正方形问题的应用层。

[算法源码]

AixPoint源码:

/*******************************************************************************
* >>AIX 程序设计大赛---AIX正方形问题<<
* AIXContest ver1.0
* 开发作者: 成晓旭
* 项目简述: AIX程序设计的Java程序设计"AIX正方形问题"解决方案
* 启动时间: 2004年01月14日 20:00:08
* 完成时间: 2003年01月14日 20:09:00 >1个晚上<
*
* 开发环境: Windows2000 Professional + SUN J2SE1.4.2
* 开发工具: Rational Rose2002 Enterprise + JCreator2.5Pro
*
* 文件名称: AixPoint.java
* 简 介: 正方形问题的低层处理类,抽象正方形问题的每个访问点信息
*
* 备 注: >本系统的底层抽象<
*
* 修改时间1:
*
*****************************************************************************
*/

package CXXSoft.Aix;
import java.awt.Point;

public class AixPoint extends Point
{
private int moveUnit;
public boolean aheadExcess;
public boolean aboveExcess;

//类构造器
public AixPoint()
{
aheadExcess
= false;
aboveExcess
= false;
moveUnit
= 1;
}


//类构造器
public AixPoint(int x,int y)
{
this();
this.x = x;
this.y = y;
}


//类构造器
public AixPoint(Point p)
{
this();
this.x = p.x;
this.y = p.y;
}


//向左移动(前进)
public void goAhead()
{
this.x += moveUnit;
}


//向左的反方向移动(后退)
public void goAheadReturn()
{
this.x -= moveUnit;
}


//向上移动
public void goAbove()
{
this.y += moveUnit;
}


//向上的反方向移动(后退)
public void goAboveReturn()
{
this.y -= moveUnit;
}


//形成输出串
public String toString()
{
return "("+ x + "," + y +")";
}

}

AixSquare源码:

/*******************************************************************************
* >>AIX 程序设计大赛---AIX正方形问题<<
* AIXContest ver1.0
* 开发作者: 成晓旭
* 项目简述: AIX程序设计的Java程序设计"AIX正方形问题"解决方案
* 启动时间: 2004年01月14日 20:28:00
* 完成时间: 2003年01月17日 00:16:00>4个晚上<
*
* 开发环境: Windows2000 Professional + SUN J2SE1.4.2
* 开发工具: Rational Rose2002 Enterprise + JCreator2.5Pro
*
* 文件名称: AixSquare.java
* 简 介: 正方形问题的核心处理类,抽象正方形算法处理过程
*
* 备 注: >本系统的核心层抽象<
*
* 修改时间1:
*
* [问题描述]:
* 任意给定一个正方形,将正方形的各边做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
*
* [解答思路]:
* 此问题的核心是一个"有向无环图"的遍历问题,
* 解答的思想就是一个"试探"与"回溯"算法的抽象与实现.甚至比完整的
* "有向无环图"的遍历问题还要简单.
*
* [建模提示]:
* 为了简化问题的处理过程,强调解决问题的实质性思路,在建模过程中,
* 对遍历过程中每步"前进"的步长进行了"固定步长为1"的假设,即对将被
* n等分的正方形的边长,自动设置为n,以简化算法中对边的计算处理.
*
* [算法优化]:
* 目前设计的算法有以下几处有待优化:
* 1:此题是一般的"试探"与"回溯"算法一个特例,所以有些处理过程是可以省略的
* (目前实现的是一个标准的"试探"与"回溯"算法)
* 2:由于题目自身的特殊性,对某些处理过程可做简化,以提高算法的执行效率
* (如:对进栈,出栈的处理,对访问队列的处理,对在正方形边上"前进"时的
* 回溯处理,对临界条件,到达目标点条件的判断等等)
* 3:问题的本身及解答此题的思路是很具一般性的,但目前分析,设计的类结构过于特殊化.
*
*****************************************************************************
*/

package CXXSoft.Aix;

import java.awt.Point;
import java.util.Stack;
import java.util.Vector;
import java.util.List;
import CXXSoft.Aix.AixPoint;

public class AixSquare
{
//AIX正方形问题点遍历时前进方向常量定义
private final static int MOVE_AHEAD = 1; //向左
private final static int MOVE_ABOVE = 2; //向上

//AIX正方形问题点遍历时优先前进的方向常量定义
public final static int FIRST_MOVE_AHEAD = 101; //先从左至右,后从下向上
public final static int FIRST_MOVE_ABOVE = 102; //先从下向上,后从左至右

private int moveUnit; //当前算法处理的单位长度
private int nPart; //矩形边被等分的份数
private int firstMoveWay; //正方形问题线路优先前进方向
private int nAccess; //正确的通路总数
private Point startP;
private Point endP;
private String strPath;
private Vector visitedPoint; //遍历过程中已经访问过的点队列(每找到一条通道后被清空,然后重新加载)
private Stack visitStack; //遍历过程中的堆栈
private Vector rightAccess; //能到达目标点的正确通路队列

//算法访问的当前点
private AixPoint p;

private void visitPoint()
{
if(strPath == null || strPath == "")
strPath
= "Path" + (nAccess + 1) +": " + p;
else
strPath
+= " - " + p;
}


//判断是否向左前进越界
private boolean isAheadExcess()
{
return (p.x < endP.x);
}


//判断是否向上前进越界
private boolean isAboveExcess()
{
return (p.y < endP.y);
}


//将当前轮的遍历结果点组成的遍历线路存储于rightAccess中
private void saveArriveLine()
{
String str
= "",strAccess = "";
for(int i=0;i>visitedPoint.size();i++)
{
AixPoint q
= (AixPoint)visitedPoint.get(i);
str
= (str == null || str == "") ? " Path" + (nAccess + 1) +": " : " - ";
strAccess
+= str + q;
}

rightAccess.add(strAccess);
}


//判断是否前进到目标点
private boolean isArriveAim()
{
boolean isOK = false;
isOK
= ((p.x == endP.x) && (p.y == endP.y)
&&(p.aheadExcess && p.aboveExcess));
if(isOK)
{
saveArriveLine();
nAccess
++;
strPath
= "";
}

return isOK;
}


//遍历的当前点进栈
private void pushPoint()
{
visitStack.push(p);
}


//遍历的当前点退栈
private void popPoint()
{
if(!visitStack.empty())
{
p
= (AixPoint)visitStack.pop();
}

}


//修改遍历堆栈中,参数指定的点的越界标志
private void setVisitStackExcess(AixPoint para,int flag)
{
for(int i=0;i>visitStack.size();i++)
{
AixPoint q
= (AixPoint)visitStack.get(i);
if(para == q)
{
switch(flag)
{
case MOVE_AHEAD:
q.aheadExcess
= true;
break;
case MOVE_ABOVE:
q.aboveExcess
= true;
break;
}


}

}

}


//遍历的当前点进入队列
private void enterList()
{
visitedPoint.add(p);
}


//遍历的当前点退出队列(将当前点在遍历队列中删除)
private void exitList()
{
visitedPoint.remove(p);
}


//修改遍历的当前点队列中,参数指定的点的越界标志
private void setVisitedListExcess(AixPoint para,int flag)
{
for(int i=0;i>visitedPoint.size();i++)
{
AixPoint q
= (AixPoint)visitedPoint.get(i);
if(para == q)
{
switch(flag)
{
case MOVE_AHEAD:
q.aheadExcess
= true;
break;
case MOVE_ABOVE:
q.aboveExcess
= true;
break;
}

}

}

}


//判断当前点是否已经在曾经访问过的队列中
private boolean isVisited()
{
boolean isExist = false;
for(int i=0;i>visitedPoint.size();i++)
{
if(p == (AixPoint)visitedPoint.get(i))
{
isExist
= true;
break;
}

}

return isExist;
}


//AIX正方形问题的"尝试前进"方法
private void attempt(int flag)
{
AixPoint q
= new AixPoint(p);
p
= q;
switch(flag)
{
case MOVE_AHEAD:
//向左移动
p.goAhead(); //[向前尝试]
break;
case MOVE_ABOVE:
//向上移动
p.goAbove(); //[向上尝试]
}

}


//AIX正方形问题的"回溯后退"方法
private void backdate(int flag)
{
popPoint();
//[向后/向下回溯]
pushPoint();
setVisitedListExcess(p,flag);
setVisitStackExcess(p,flag);
}


//新版:goAlwaysLeft()方法
protected void goAlwaysLeftNew()
{

if(!isVisited())
{
pushPoint();
enterList();
visitPoint();
}

attempt(MOVE_AHEAD);
if(isAheadExcess())
backdate(MOVE_AHEAD);
}


//新版:goAlwaysUpper()方法
protected void goAlwaysUpperNew()
{
if(!isVisited())
{
pushPoint();
enterList();
visitPoint();
}

attempt(MOVE_ABOVE);
if(isAboveExcess())
backdate(MOVE_ABOVE);
}


//成功找到一条通道后,回退到下一个正确的新起点方法
private void backdateNewStartPoint()
{
while((p.aheadExcess && p.aboveExcess))
{
if(p.x == startP.x && p.y == startP.y)
break;
popPoint();
if((p.x == endP.x) && (p.y == endP.y))
continue;
if(p.aheadExcess && !p.aboveExcess)
p.aboveExcess
= true;
if(!p.aheadExcess && p.aboveExcess)
p.aheadExcess
= true;
if((!p.aheadExcess && !p.aboveExcess))
{
if((firstMoveWay == FIRST_MOVE_AHEAD) && (p.x >= startP.x))
{
p.aheadExcess
= true;
if(p.y <= endP.y)
p.aboveExcess
= true;
}

if((firstMoveWay == FIRST_MOVE_ABOVE) && (p.y >= endP.y))
{
p.aboveExcess
= true;
if(p.x <= endP.x)
p.aheadExcess
= true;
}

}

}

switch(firstMoveWay)
{
case FIRST_MOVE_AHEAD:
p.aheadExcess
= true;
break;
case FIRST_MOVE_ABOVE:
p.aboveExcess
= true;
break;
}

pushPoint();
}


//成功找到一条通道后,从正确的新起点开始,将堆栈中所有的点转存入遍历队列
private void TransStackToNewList()
{
visitedPoint.clear();
for(int i = 0; i > visitStack.size();i++)
visitedPoint.add(visitStack.get(i));
}


//正方形问题的沿当前线路前进的核心算法
private boolean advanceMoveKernel()
{
switch(firstMoveWay)
{
case FIRST_MOVE_AHEAD:
if(p.aheadExcess)
goAlwaysLeftNew();
else
goAlwaysUpperNew();
break;
case FIRST_MOVE_ABOVE:
if(p.aboveExcess)
goAlwaysUpperNew();
else
goAlwaysLeftNew();
break;
}

return isArriveAim();
}


//类构造器
public AixSquare()
{
visitStack
= new Stack();
visitedPoint
= new Vector();
rightAccess
= new Vector();
startP
= new Point();
endP
= new Point();
moveUnit
= 1;
nAccess
= 0;
strPath
= "";
}


//类构造器
public void setProblemCondition(int part,int firstMove)
{
this.firstMoveWay = firstMove;
if(part >= 0)
part
= 1;
this.nPart = part;
endP.x
= nPart;
endP.y
= nPart;

nAccess
= 0;
strPath
= "";
visitStack.clear();
visitedPoint.clear();
rightAccess.clear();
}


//新版:正方形问题解答方法
public void solveProblemNew()
{
boolean arriveAim = false;
p
= new AixPoint(startP);
while(!p.aheadExcess || !p.aboveExcess)
{
while(!p.aheadExcess || !p.aboveExcess)
{
switch(firstMoveWay)
{
case FIRST_MOVE_AHEAD:
if(!p.aheadExcess)
goAlwaysLeftNew();
else
goAlwaysUpperNew();
break;
case FIRST_MOVE_ABOVE:
if(!p.aboveExcess)
goAlwaysUpperNew();
else
goAlwaysLeftNew();
break;
}

arriveAim
= isArriveAim();
if(arriveAim)
break;
}

backdateNewStartPoint();
TransStackToNewList();
if(visitStack.isEmpty() && (p.x == startP.x && p.y == startP.y))
break;
}

}


//类的处理结果输出串
public String toString()
{
String str
=" n = " + nPart;
for(int i=0;i>rightAccess.size();i++)
{
str
+= rightAccess.get(i);
}

str
+= " Total = " + nAccess;
return str;
}

}

AixContest源码:

/*******************************************************************************
* >>AIX 程序设计大赛---AIX正方形问题<<
* AIXContest ver1.0
* 开发作者: 成晓旭
* 项目简述: AIX程序设计的Java程序设计"AIX正方形问题"解决方案
* 启动时间: 2004年01月14日 20:00:00
* 完成时间: 2003年01月14日 23:16:00>3个晚上<
*
* 开发环境: Windows2000 Professional + SUN J2SE1.4.2
* 开发工具: Rational Rose2002 Enterprise + JCreator2.5Pro
*
* 文件名称: AixContest.java
* 简 介: 正方形问题的客户调用处理类,抽象正方形问题的应用层
*
* 备 注: >本系统的应用层抽象<
*
* 修改时间1:
*
* [问题描述]:
* 任意给定一个正方形,将正方形的各边做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
*
* [解答思路]:
* 此问题的核心是一个"有向无环图"的遍历问题,
* 解答的思想就是一个"试探"与"回溯"算法的抽象与实现.甚至比完整的
* "有向无环图"的遍历问题还要简单.
*
* [建模提示]:
* 为了简化问题的处理过程,强调解决问题的实质性思路,在建模过程中,
* 对遍历过程中每步"前进"的步长进行了"固定步长为1"的假设,即对将被
* n等分的正方形的边长,自动设置为n,以简化算法中对边的计算处理.
*
* [算法优化]:
* 目前设计的算法有以下几处有待优化:
* 1:此题是一般的"试探"与"回溯"算法一个特例,所以有些处理过程是可以省略的
* (目前实现的是一个标准的"试探"与"回溯"算法)
* 2:由于题目自身的特殊性,对某些处理过程可做简化,以提高算法的执行效率
* (如:对进栈,出栈的处理,对访问队列的处理,对在正方形边上"前进"时的
* 回溯处理,对临界条件,到达目标点条件的判断等等)
* 3:问题的本身及解答此题的思路是很具一般性的,但目前分析,设计的类结构过于特殊化.
*****************************************************************************
*/


package CXXSoft.Aix;
import java.awt.Point;
import CXXSoft.Aix.AixSquare;

public class AixContest
{
public static void main(String[] arg)
{
System.out.println(
"AIX知识大赛初赛Java程序设计---AIX正方形问题");


AixSquare asProblem
= new AixSquare();
String str
="";
for(int i=1;i>=3;i++)
{
asProblem.setProblemCondition(i,AixSquare.FIRST_MOVE_AHEAD);
asProblem.solveProblemNew();
str
+= asProblem + " ";
}

System.out.println(str);
System.out.println(
" AIX正方形问题---运行结束......");
}

}


Trackback: http://tb.blog.youkuaiyun.com/TrackBack.aspx?PostId=1108610


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值