import java.util.HashMap;
import java.util.Iterator;
import java.util.Stack;
/**
* 编程解决以下问题:
* 3只大老虎(A、B、C)和3只小老虎(a、b、c)过河,过河的工具是一条小船,
* 3只大老虎和其中一条小老虎(a)会划船,船一次只能载不管大小2个老虎
* 过河,但是小老虎必须和母亲在一起,否则就会被其他大老虎吃掉,看看
* 怎么样过河能保证不被大老虎吃掉安全过河。
*
* 实现思路
* 1. 初始状态(都在河左岸0000 0000) ----> 终止状态(都在河右岸0111 1111)
* 2. 状态表示位表示:0-船, 1-老虎A, 2-老虎a, 3-老虎B, 4-老虎b, 5-老虎C, 6-老虎c, 此位为0表示在左岸,为1表示在右岸;
* 3. 构造从初始状态到一下个合法状态有向图.
* 4. 构造图一直到没有下一个状态,或者到了终止状态结束停止构造.
* 5. 构造图的过程使用广度优先一层一层构造.
* 6. 递归构造图的过程中如果发现终止结点就返回true,如果返回true就用栈保存当前结点,
* 从而在递归返回过程中形成一条到终止结点状态转换路径;
* 递归返回过程得到结果,省去搜索图;
*/
public class TigerAcrossRiver {
private static final int SHIP = 0;
private static final int TOTAL_STATUS = 7;
private static final int BEGIN_STATUS = 0x0; // 初始状态--全都在左岸(0000 0000)
private static final int END_STATUS = 0x7F; // 终止状态--全都在右岸(0111 1111)
// 0000 0010 ; A ; 1 << 1
// 0000 0100 ; a ; 1 << 2
// 0000 1000 ; B ; 1 << 3
// 0010 0000 ; C ; 1 << 5
// 0010 1110 为判断划船者提供方便;
private static final int SAILOR = 0x2E;
private static HashMap<Integer, Integer> traceMap = new HashMap<Integer, Integer>();
private static Stack<Node> step = new Stack<Node>();
/**
* 创建一个有向无环图; 创建过程中可以顺便保存路径,省去再搜索图;
*/
private static boolean createNodeTree(Node curNode) {
if (curNode == null) {
return false;
}
int status = curNode.status;
// 已经是终止状态
if (isSucceed(status)) {
return true;
}
HashMap<Integer, Node> ret = new HashMap<Integer, Node>();
if (isRight(status, SHIP)) {// 如果船在右岸
for (int j = 1; j < TOTAL_STATUS; j++) {// 编历6个动物;
if (isRight(status, j) && isSailor(j)) {// 如果在右岸且会划船的;
// 设定划船者,分两种情况,1划船者单独过河,2划船者带一名乘客;
int statusTmp = setLeft(setLeft(status, SHIP), j);
if (isStatusLegal(statusTmp)) {// 如果单独划船也合法状态也添加到next状态集中;
ret.put(statusTmp, new Node(statusTmp, null));
}
// 带乘客,除划船的只有载一名乘客;
int statusTmp2;
for (int k = 1; k < TOTAL_STATUS; k++) {// 6只动物
if (isRight(statusTmp, k)) {// 在右岸;
statusTmp2 = setLeft(statusTmp, k); // 同划船都一起过河
if (isStatusLegal(statusTmp2)) {// 合法则加入结果集;
ret.put(statusTmp2, new Node(statusTmp2, null));
}
}
}
}
}
} else {// 如果船在左岸
for (int j = 1; j < TOTAL_STATUS; j++) {// 编历6只动物;
if (!isRight(status, j) && isSailor(j)) {// 在左岸且会划船
int statusTmp = setRight(setRight(status, SHIP), j);
if (isStatusLegal(statusTmp)) {
ret.put(statusTmp, new Node(statusTmp, null));
}
// 带乘客,除划船的只有载一名乘客;
int statusTmp2;
for (int k = 1; k < TOTAL_STATUS; k++) {// 编历6只动物;
if (!isRight(statusTmp, k)) {// 在左岸
statusTmp2 = setRight(statusTmp, k); // 过河到右岸;
if (isStatusLegal(statusTmp2)) {// 合法加入next结果集;
ret.put(statusTmp2, new Node(statusTmp2, null));
}
}
}
}
}
}
if (ret.size() == 0) {
return false;
}
curNode.next = ret;
for (Iterator it = ret.keySet().iterator(); it.hasNext();) {
Integer key = (Integer)it.next();
Node d = ret.get(key);
if (createNodeTree(d)) {
step.push(d);
return true;
}
}
return false;
}
// 将sb移到右岸;
private static int setRight(int status, int sb) {
return status | (1 << sb);
}
// 将sb移到左岸;
private static int setLeft(int status, int sb) {
return status & ((~0) ^ (1 << sb));
}
// 判断是否终止状态;
private static boolean isSucceed(int status) {
return (status == END_STATUS) ? true : false;
}
// 判断sb会不会划船的
private static boolean isSailor(int sb) {
return (SAILOR & (1 << sb)) == (1 << sb);
}
// 判断是否是合法状态;
private static boolean isStatusLegal(int status) {
for (int i = 1; i < TOTAL_STATUS; i += 2) {// 编历6只动物
// 如果父子不在同岸,i是大老虎,i+1就是小老虎;
if (isRight(status, i) ^ isRight(status, i + 1)) {
// 那么另外两只大老虎不能和i+1在一起, 否则不安全return false;
if (
(isRight(status, (i + 2) % 6) ^ isRight(status, i + 1)) /* 以6为模找另两只大虎中的一只 */
&& (isRight(status, (i + 4) % 6) ^ isRight(status, i + 1)) /* 另外两只大虎中第二只 */
) {
continue;
}
else
{
//不安全return false;
return false;
}
}
}
if (traceMap.containsKey(status)) {
// 已经编历过的结点不用再处理
// 这里return false是为了不加入next子结点集,确保有向图无环;
return false;
} else {
traceMap.put(status, status);
}
return true;
}
// 检查当前状态下,sb是否在右岸;
private static boolean isRight(int status, int sb) {
return (status & (1 << sb)) == (1 << sb);
}
static class Node {
public Node(int s, HashMap<Integer, Node> n) {
this.status = s;
this.next = n;
}
public int status;
public HashMap<Integer, Node> next;
}
// 打印当前状态
private static void printStatus(int status) {
StringBuffer strTmp = new StringBuffer("AaBbCc|> <|AaBbCc");
if (isRight(status, SHIP)) {
strTmp.replace(7, 8, " ");
} else {
strTmp.replace(10, 11, " ");
}
for (int i = 1; i < TOTAL_STATUS; i++) {
if (isRight(status, i)) {
strTmp.replace(i - 1, i, " ");
} else {
strTmp.replace(i + 11, i + 12, " ");
}
}
System.out.println(strTmp);
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
System.out.println("Start time : " + startTime);
Node root = new Node(BEGIN_STATUS, null);
traceMap.put(BEGIN_STATUS, BEGIN_STATUS);
createNodeTree(root);
step.push(root);
for (int i = step.size() - 1; i >= 0; i--) {
printStatus(step.get(i).status);
}
long endTime = System.currentTimeMillis();
System.out.print("End time : " + endTime + ", cost "
+ (endTime - startTime) + "ms");
}
}
Start time : 1364219778187
AaBbCc|> |
A BbC | <| a c
AaBbC |> | c
A B C | <| a b c
AaB C |> | b c
Aa | <| BbCc
AaBb |> | Cc
Bb | <|Aa Cc
BbCc|> |Aa
b c| <|AaB C
a b c|> |A B C
b | <|AaB Cc
Bb |> |Aa Cc
| <|AaBbCc
End time : 1364219778187, cost 0ms