/**
*
* @author z84002131
* 很久很久以前,在一个森林里,有狮子,老虎和狼,他们应大象的邀请,要到大象家做客。去的路上被一条小河拦住了,需要过河,只有一个独木舟。现在已知:
* 1.总共有6只,分别是狮子爸爸,小狮子,老虎爸爸,小老虎,狼爸爸和小狼。
* 2.小家伙们都比较弱小,如果没有爸爸罩着就会被旁边的大家伙吃掉。
* 3.独木舟最多能坐2人,无视每只的大小。
* 4.大家伙都会划船,小家伙里只有小老虎会划船。
* 求:安全过河方法。
* 提示:可以设大狮子为A,小狮子为a,大老虎为B,小老虎为b,大狼为C,小狼为c。再形象的用竖线来表示河,0表示船,那么题目就是要求画出
* AaBbCc|0 |
* ...
* | 0|AaBbCc
* 中间被...省略的步骤
*/
import java.util.Vector;
public class AcrossTheRiver {
private static final int SHIP = 0;
private static final int LION_A = 1;
private static final int LION_a = 2;
private static final int TIGER_B = 3;
private static final int TIGER_b = 4;
private static final int WOLF_C = 5;
private static final int WOLF_c = 6;
private static final int TOTAL_STATUS = 7;
//用一个整型int来存放当前的状态,第1位为0表示SHIP在左岸,第1位为1表示SHIP在右岸
// 第2位为0表示LION_A在左岸,第2位为1表示LION_A在右岸
// 第3位为0表示LION_a在左岸,第3位为1表示LION_a在右岸,往下以此类推
private static final int BEGIN_STATUS = 0;//初始状态全都在左岸
private static final int END_STATUS = 0x7F;//目的是都到右岸去
private static final int SAILOR = (1 << LION_A) | (1 << TIGER_B) | (1 << TIGER_b) | (1 << WOLF_C);
private static Vector<Integer> stepVec = new Vector<Integer>();//存放摆渡的步骤,用于最后输出步骤
//存放每个场景可能的下一步场景
//考虑到一共有6兽1船共7个物体,每个物体有左岸和右岸两个状态,因此一共有2的7次方共128个场景。
//每个场景的下一步,仅有数种可能的场景:如AaBb|0 |Cc的下一步中,仅有Aa| 0|BbCc和Bb| 0|AaCc这两个合法的场景
//利用这张表,可以方便的预测出下一步可能的动作,从而进行推演
private static Vector<Integer>[] traceMap = createTraceMap();
//创建traceMap
private static Vector<Integer>[] createTraceMap(){
//建立场景表traceMap
Vector<Integer>[] traceMapTmp = new Vector[1 << TOTAL_STATUS];
//int iCount = 0;
for(int i = 0; i < (1 << TOTAL_STATUS); i++){
traceMapTmp[i] = new Vector<Integer>();
if(!isStatusLegal(i)){//如果当前状态不合法就不用再看了
continue;
}
//printStatus(i);
int statusTmp;
if(isRight(i, SHIP)){//如果船在右岸
for(int j = 1; j < TOTAL_STATUS; j++){
if(isRight(i, j) && isSailor(j)){
//决定划船的
statusTmp = setLeft(setLeft(i, SHIP), j);
if(isStatusLegal(statusTmp)){
traceMapTmp[i].add(new Integer(statusTmp));
//iCount++;
//printStatus(statusTmp);
}
//决定是否带乘客
int statusTmp2;
for(int k = 1; k < TOTAL_STATUS; k++){
if(isRight(statusTmp, k)){
statusTmp2 = setLeft(statusTmp, k);
if(isStatusLegal(statusTmp2)){
traceMapTmp[i].add(new Integer(statusTmp2));
//iCount++;
//printStatus(statusTmp2);
}
}
}
}
}
} else {//如果船在左岸
for(int j = 1; j < TOTAL_STATUS; j++){
if(!isRight(i, j) && isSailor(j)){
//决定划船的
statusTmp = setRight(setRight(i, SHIP), j);
if(isStatusLegal(statusTmp)){
traceMapTmp[i].add(new Integer(statusTmp));
//iCount++;
//printStatus(statusTmp);
}
//决定是否带乘客
int statusTmp2;
for(int k = 1; k < TOTAL_STATUS; k++){
if(!isRight(statusTmp, k)){
statusTmp2 = setRight(statusTmp, k);
if(isStatusLegal(statusTmp2)){
traceMapTmp[i].add(new Integer(statusTmp2));
//iCount++;
//printStatus(statusTmp2);
}
}
}
}
}
}
//System.out.println("\n");
}
//System.out.println("iCount = " + iCount);
return traceMapTmp;
}//end of createTraceMap
//摆渡
private static boolean goTowards(int status){
//判断是否胜利了
if(isSucceed(status)){
stepVec.add(new Integer(status));
return true;
}
if(stepVec.indexOf(status) == -1){//如果是之前没遇过的场景,可以继续走着看看
stepVec.add(new Integer(status));
}else{//如果转回了之前的场景,那就放弃这种走法
return false;
}
for(int i = 0; i < traceMap[status].size(); i++){//穷举每个可能的下一步场景继续分析
if(goTowards(traceMap[status].elementAt(i).intValue())){//递归深入 穷举
return true;
}
}
stepVec.remove(stepVec.size() - 1);//如果没找到
return false;
}
//判断胜利条件
private static boolean isSucceed(int status){
return (status == END_STATUS) ? true : false;
}
//判断会不会划船的
private static boolean isSailor(int animal){
return (SAILOR & (1 << animal)) == (1 << animal);
}
//检查在status状态下,编号为animal的兽是否在右岸
private static boolean isRight(int status, int animal){
return (status & (1 << animal)) == (1 << animal);
}
//将某兽移动到左边
private static int setLeft(int status, int animal){
return status & ((~0)^(1 << animal));
}
//将某兽移动到右边
private static int setRight(int status, int animal){
return status | (1 << animal);
}
//判断当前情况是否有小兽成为牺牲品
private static boolean isStatusLegal(int status){
for(int i = 1; i < TOTAL_STATUS; i += 2){
while(true){
//如果父子不在同岸
if(isRight(status, i) ^ isRight(status, i + 1)){
//那么另外两只大兽必须和父亲在同一边
if((isRight(status, (i + 2) % 6) ^ isRight(status, i + 1))
&& (isRight(status, (i + 4) % 6) ^ isRight(status, i + 1))){
break;
}
//否则小兽就挂了
return false;
//如果父子同岸,那么有大兽保护,小兽没问题
}else {
break;
}
}
}
return true;
}
//打印当前状态
private static void printStatus(int status){
StringBuffer strTmp = new StringBuffer("AaBbCc|0 0|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);
}
//打印出步骤结果
private static void showStep(){
goTowards(BEGIN_STATUS);
for(int i = 0; i < stepVec.size(); i++){
printStatus(stepVec.elementAt(i).intValue());
}
}
public static void main(String[] args) {
showStep();
}
}