1. 程式人生 > >農夫運送貓狗魚過河問題(面向物件)

農夫運送貓狗魚過河問題(面向物件)

題設:農夫欲用船將左岸的貓、狗、魚運送到右岸。在運送的過程中,每次只能運送一隻動物,農夫也可以空船過河。其中當人不在此岸時,狗會咬貓;貓會吃魚。當人在此岸時,則不會發生衝突。請用面向物件的設計思想解決此類問題。

分析:通過題設條件可以得出以下結論:1、左到右,不存在從左岸到右岸的空船(也就是從左岸到右岸必須運送一隻動物);2、右到左,有且只有兩種情況:①空船過河、②帶一隻動物過河。

程式設計:5個類:MyCrossRiver.java、CrossProcess.java、CrossStep.java、Status.java、Animal.java。其中,MyCrossRiver是程式執行的主類,也包含了過河邏輯;CrossProsess是記錄整個過程已經走過的正確的步驟序列;CrossStep表示的是所走過的每一步;Status表示的是對當前步驟的狀態的封裝(對於左岸和右岸的資料是深度拷貝);Animal是動物的抽象。

主要程式碼如下:

MyCrossRiver.java:

package com.others;

import java.util.ArrayList;
import java.util.List;

/**
 * 貓狗魚過河問題
 * @author xuefeihu
 *
 */
public class MyCrossRiver {
	/** 河左岸 **/
	private List<Animal> left = new ArrayList<Animal>();
	/** 河右岸 **/
	private List<Animal> right = new ArrayList<Animal>();
	/** 人的位置:左邊是true,右邊是false **/
	private boolean flag = true;
	/** 過河步驟 **/
	private CrossProcess process = new CrossProcess();
	
	public static void main(String[] args) {
		new MyCrossRiver().crossRiver();
	}
	
	/**
	 * 初始化條件
	 */
	public void initAnimal(){
		Animal dog = new Animal("狗", 1, -1, 2);
		Animal cat = new Animal("貓", 2, 1, 3);
		Animal fish = new Animal("魚", 3, 2, -1);
		left.add(dog);
		left.add(cat);
		left.add(fish);
	}
	
	/**
	 * 過河操作
	 */
	public void crossRiver(){
		initAnimal();
		while(right.size() != 3){
			Status preStatus = new Status(this.left, this.right, this.flag);//記錄步驟前狀態
			CrossStep step = new CrossStep(process.getStepCount()+1, this.flag, null, preStatus);//建立步驟
			if(this.flag){//從左到右過河(不存在空船過河)
				int leftIndex = step.getNextLeftIndex();
				int leftSize = this.left.size();
				if(leftIndex >= leftSize){//回退資料
					this.process.removeLastStep();
					CrossStep step2 = this.process.getLastStep();
					this.back2Step(step2);
					continue;
				}else{//帶動物過河
					step.setAnimal(this.left.get(leftIndex));
				}
			}else{//從右往左過河
				Animal animal = null;
				boolean rightSecurity = this.check(right);
				if(rightSecurity){
					animal = this.getTargetAnimal(this.right);
					if(animal == null){//衝突無法解決時,回退資料
						this.process.removeLastStep();
						CrossStep step2 = this.process.getLastStep();
						this.back2Step(step2);
						continue;
					}else{
						step.setAnimal(animal);
					}
				}else{//無衝突時,不運送動物
					step.setAnimal(null);
				}
			}
			
			boolean result = moveByOneStep(step);
			if(!result){//如果執行失敗,則恢復上一步驟
				this.process.removeLastStep();
				CrossStep step2 = this.process.getLastStep();
				this.back2Step(step2);
			}
			
		}
		this.process.printStepMessage();
	}
	
	/**
	 * 移動操作
	 * @param step
	 * @return 返回true表示轉移成功,false表示轉移失敗(失敗時需要回退到上一步進行轉移)
	 */
	public boolean moveByOneStep(CrossStep step){
		/** 返回的結果:true表示移動成功、false表示失敗 **/
		boolean result = false;
		/** 迴圈標誌位 **/
		boolean cricleFlag = false;
		
		while(!cricleFlag){
			int leftIndex = step.getNextLeftIndex();
			int leftSize = step.getStatus().getLeft().size();
			int rightIndex = step.getNextRightIndex();
			if(this.flag){//當可以找到下一個索引時,進行轉移
				if(leftIndex < leftSize){//帶動物過河
					Animal animal = left.remove(leftIndex);
					right.add(animal);
					flag = !flag;
					step.setAnimal(animal);
				}else if(leftIndex >= leftSize){
					return false;//返回失敗資訊,並交給上一層程式處理
				}
			}else if(!this.flag){
				if(step.getAnimal() == null){//此時可以單人過河
					flag = !flag;
					this.process.addStep(step);
					return true;
				}else{//帶動物過河
					Animal animal = right.remove(rightIndex);
					left.add(animal);
					flag = !flag;
				}
			}
			
			//檢查衝突情況(轉移後回退)
			if(!this.flag && check(this.left)){
				step.addNextLeftIndex();
				this.back2Step(step);
			}else if(this.flag && check(this.right)){
				step.addNextRightIndex();
				this.back2Step(step);
			}else {
				this.process.addStep(step);
				result = true;
				cricleFlag = true;
			}
		}
		
		return result;
	}
	
	/**
	 * 將當前狀態恢復到step步驟
	 * @param step
	 */
	private void back2Step(CrossStep step){
		Status status = step.getStatus();
		this.left = status.getLeft();
		this.right = status.getRight();
		this.flag = status.getFlag();
	}
	
	/**
	 * 從衝突的資料中獲取不衝突的動物:不存在時返回null
	 */
	public Animal getTargetAnimal(List<Animal> array){
		Animal result = null;
		//克隆物件
		List<Animal> lists = new ArrayList<Animal>();
		Animal target = null;
		Animal source = null;
		for(int i = 0; i < array.size(); i++){
			source = array.get(i);
			target = new Animal(source.type, source.id, source.afraid, source.control);
			lists.add(target);
		}
		//查詢物件
		for(int i = 0; i < lists.size(); i++){
			result = lists.remove(i);
			if(!check(lists)){
				break;
			}
			lists.add(i, result);
		}
		return result;
	}

	/**
	 * 檢查是否有衝突
	 */
	private boolean check(List<Animal> array){
		boolean result = true;
		if(array.size() > 1){
			for(int i = 0; i < array.size(); i++){
				for(int j = i+1; j < array.size(); j++){
					result = array.get(i).check(array.get(j));
					if(result) return result;
				}
			}
		}else{
			result = false;
		}
		return result;
	}
	
}
CrossProcess.java
package com.others;

import java.util.ArrayList;
import java.util.List;

/**
 * 過河的過程
 * @author xuefeihu
 *
 */
public class CrossProcess {
	/** 所有步驟 **/
	private List<CrossStep> steps = new ArrayList<CrossStep>();
	
	/**
	 * 新增步驟
	 * @param step 步驟
	 */
	public void addStep(CrossStep step){
		if(step.getDirection()){
			step.addNextLeftIndex();
		}else{
			step.addNextRightIndex();
		}
		this.steps.add(step);
	}
	
	/**
	 * 刪除最後一步
	 */
	public CrossStep removeLastStep(){
		return this.steps.remove(this.steps.size()-1);
	}
	
	/**
	 * 獲取最後一個步驟
	 * @return
	 */
	public CrossStep getLastStep(){
		return this.steps.get(this.steps.size()-1);
	}
	
	/**
	 * 列印步驟資訊
	 */
	public void printStepMessage(){
		for(CrossStep step : steps){
			System.out.println(step.getMessage());
		}
	}
	
	/**
	 * 獲得當前步驟數
	 * @return
	 */
	public int getStepCount(){
		return this.steps.size();
	}
	
}

CrossStep.java

package com.sunrise.others;
/**
 * 過河步驟
 * @author xuefeihu
 *
 */
public class CrossStep {
	/** 步驟數 **/
	private int stepCount;
	/** 方向:true是左到右,false是右到左 **/
	private boolean direction;
	/** 此步驟運送的動物 **/
	private Animal animal;
	/** 該步驟之前狀態 **/
	private Status status;
	/** 列印語句 **/
	private String message;
	/** 下一個左側需要移動的索引 **/
	private int nextLeftIndex = 0;
	/** 下一個右側需要移動的索引 **/
	private int nextRightIndex = 0;
	
	/**
	 * 構造器
	 * @param stepCount 步驟數
	 * @param direction 方向:true是左到右,false是右到左
	 * @param animal 此步驟運送的動物
	 * @param status 當前狀態
	 */
	public CrossStep(int stepCount, boolean direction, Animal animal, Status status) {
		this.stepCount = stepCount;
		this.direction = direction;
		this.animal = animal;
		this.status = status;
		this.message = "第"+stepCount+"步:農夫將" + (this.animal==null?" 自己 ":this.animal.type) + (this.direction ? "從左岸運到右岸" : "從右岸運到左岸");
	}

	public int getStepCount() {
		return stepCount;
	}

	public boolean getDirection() {
		return direction;
	}

	public Animal getAnimal() {
		return animal;
	}

	public Status getStatus() {
		return status;
	}

	public String getMessage() {
		return message;
	}

	public int getNextLeftIndex() {
		return nextLeftIndex;
	}

	public void addNextLeftIndex() {
		this.nextLeftIndex++;
	}
	
	public int getNextRightIndex() {
		return nextRightIndex;
	}

	public void addNextRightIndex() {
		this.nextRightIndex++;
	}
	
	public void setAnimal(Animal animal) {
		this.animal = animal;
		this.message = "第"+stepCount+"步:農夫將" + (this.animal==null?" 自己 ":this.animal.type) + (this.direction ? "從左岸運到右岸" : "從右岸運到左岸");
	}
	
}

Status.java
package com.sunrise.others;

import java.util.ArrayList;
import java.util.List;

/**
 * 當前狀態
 * @author xuefeihu
 *
 */
public class Status {
	/** 左側 **/
	private List<Animal> left = new ArrayList<Animal>();
	/** 右側 **/
	private List<Animal> right = new ArrayList<Animal>();
	/** 人的位置 **/
	private boolean flag;
	
	/**
	 * 構造狀態物件--克隆相應資料
	 * @param left 左側狀態
	 * @param right 右側狀態
	 * @param flag 人的位置
	 * @param preSelf 前一個動作是否是人單獨過河
	 */
	public Status(List<Animal> left, List<Animal> right, boolean flag) {
		this.left = newList(left);
		this.right = newList(right);
		this.flag = flag;
	}
	
	/**
	 * 克隆List物件
	 */
	private List<Animal> newList(List<Animal> array){
		List<Animal> result = new ArrayList<Animal>();
		for(Animal animal : array){
			result.add(animal);
		}
		return result;
	}

	public List<Animal> getLeft() {
		return left;
	}

	public List<Animal> getRight() {
		return right;
	}

	public boolean getFlag() {
		return flag;
	}

}

Animal.java
package com.sunrise.others;
/**
 * 動物實體
 * @author xuefeihu
 *
 */
public class Animal {
	public String type = null;
	public int id = -1;
	public int afraid = -1;
	public int control = -1;
	
	public Animal(String type, int id, int afraid, int control) {
		this.type = type;
		this.id = id;
		this.afraid = afraid;
		this.control = control;
	}

	/**
	 * 設計一個制約關係:檢查動物是否可以並存
	 * @param animal
	 * @return
	 */
	boolean check(Animal animal){
		return this.afraid == animal.id || this.control == animal.id 
				|| animal.afraid == this.id || animal.control == this.id;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Animal other = (Animal) obj;
		if (id != other.id)
			return false;
		return true;
	}
	
}

友情提示:(面向物件的思想大致認為是正確的;由於時間倉促,如有修改程式碼,請您附上原始碼與大家共享,謝謝!)再見