农夫运送猫狗鱼过河问题(面向对象)

题设:农夫欲用船将左岸的猫、狗、鱼运送到右岸。在运送的过程中,每次只能运送一只动物,农夫也可以空船过河。其中当人不在此岸时,狗会咬猫;猫会吃鱼。当人在此岸时,则不会发生冲突。请用面向对象的设计思想解决此类问题。

分析:通过题设条件可以得出以下结论: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;
	}

}

友情提示:(面向对象的思想大致认为是正确的;由于时间仓促,如有修改代码,请您附上源码与大家共享,谢谢!)

时间: 2024-10-27 05:53:44

农夫运送猫狗鱼过河问题(面向对象)的相关文章

养殖者运送猫狗过河问题(面向对象)

让标题:农民希望猫左岸用船.狗.鱼运至右岸. 在运输过程中,每次只能运送一个单纯的动物.过河农民可以空船. 当中当人不在此岸时,狗会咬猫.猫会吃鱼.当人在此岸时,则不会发生冲突. 请用面向对象的设计思想解决此类问题. 分析:通过题设条件能够得出下面结论:1.左到右,不存在从左岸到右岸的空船(也就是从左岸到右岸必须运送一仅仅动物):2.右到左.有且仅仅有两种情况:①空船过河.②带一仅仅动物过河. 程序设计:5个类:MyCrossRiver.java.CrossProcess.java.CrossS

猫抓老鼠-Java面向对象特点梳理

我们先设计一个猫抓老鼠的小游戏: ⊙猫和老鼠都有名字和体重两种属性,猫有抓老鼠的方法,对应的老鼠则有逃跑的方法. ⊙首先游戏的结果是猫抓住了老鼠或者老鼠逃跑了,对于这两种情况,我们用体重来区分,若猫的体重大于或等于老鼠的体重,则猫可实现抓住老鼠的方法,若猫的体重小于老鼠的体重,则老鼠实现了逃跑的方法. 分析一下,第一步我们需要建立两个类:Cat.Mouse:并且分别声明其各自拥有的方法:  //Cat.java package Testprogramming //打包语句,将Cat类存于Test

黑马程序员_面向对象解决的一个小问题,觉得还好,就存一下

/** *10. 一位老农带着猫.狗.鱼过河,河边有一条船,每次老农只能带一只动物过河. *当老农不和猫狗鱼在一起时,狗会咬猫,猫会吃鱼,当老农和猫狗鱼在一起时,则不会发生这种问题. *编程解决猫狗鱼过河问题. * *分析: * 问题中的对象:猫.狗.鱼.老农.岸1(这岸).岸2(对岸) * * * 限制条件是:老农每次只能带一只动物过河 * 老农不在时,狗咬猫 * 老农不在时,猫吃鱼 * 目标是:将猫.狗.鱼从这岸运到对岸. * 当农夫到达一个岸后,即为一个中间状态,则这个中间状态需要满足,岸

九度OJ 题目1204:农夫、羊、菜和狼的故事

思路:广度 优先  记录路径长度  但是题目的意思好像是要记录具体路径  下次再搞吧 题目描述: 有一个农夫带一只羊.一筐菜和一只狼过河.果没有农夫看管,则狼要吃羊,羊要吃菜.但是船很小,只够农夫带一样东西过河.问农夫该如何解此难题? 输入: 题目没有任何输入. 输出: 题目可能有种解决方法,求出步骤最少的解决方法,按顺序输出农夫想把羊.菜.狼全部运过河需要哪几个步骤.如果需要将羊带过河去则输出"sheep_go".如果需要将羊带回来则输出"sheep_come".

过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(第2届第2题)

题目要求 问题描述:三只牛三只虎过河,船最多只能容纳两只动物,且船在往返途中不能为空.在任一岸边,若牛的数量少于虎的数量,则牛就会被老虎吃掉.为了使动物全部过河且使无损失,请制定合理的渡河方案. 解决方案 这也是一个经典的渡河问题了,由此衍化出的版本有商人仆人(随从)过河,农夫妖怪过河,传教士野人过河...除了角色有变化,内容本质上是一样的. 假设原来的动物和船都在A岸,现在想渡河到对面的B岸.考虑牛虎数量和船的位置,可以将本题中的所有可能出现的情形描述为静态属性和动态属性.静态属性就是船停靠在

农夫过河问题算法设计与实现

一个农夫带着-只狼.一只羊和-棵白菜,身处河的南岸.他要把这些东西全部运到北岸.他面前只有一条小船,船只能容下他和-件物品,另外只有农夫才能撑船.如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜.请求出农夫将所有的东西运过河的方案. 实现上述求解的搜索过程可以采用两种不同的策略:一种广度优先搜索,另一种深度优先搜索.这里介绍在广度优先搜索方法中采用的数据结构设计. 程序源码: /*************

数据结构设计——农夫过河问题

农夫过河问题 1. 问题描述: 设有一个农夫带一只狼,一只羊和一筐菜来到河边,打算乘一只船从右岸渡到左岸去.该船的负载能力为农夫每次只能带一样东西过河.在无农夫的时候,狼和羊不能在一起,羊和菜不能在一起.设计一个方案,使农夫可以无损失地渡过河. 2. 设计思路: 设计好图的结构,点以(农夫,狼,羊,菜)表示,设置图的点集,边集,点数,边数: 用is_safe函数确定图中各点是否安全,将不安全的点去掉,剩下安全的点,然后判断两点之间是否可变换,再通过层次遍历找到路径,设定好参数,打印出路径: 3.

农夫过河

#include <iostream>//#include <windows.h>#define STEP 20using namespace std;int m=0,n=0;/*m为take函数执行次数,n为for循环次数*/int a[STEP][4];/*0狼 1羊 2菜 3人*/int b[STEP];int count = 0;void disp(int s, int n);void take(int step);void farmer() { int i, j; for

Java面向对象练习输出猫信息

package com.text_1; public class cat { //按要求编写Java应用程序. //(1)建立一个名叫Cat的类: //属性:姓名.毛色.年龄 //行为:显示姓名.喊叫 //(2)编写主类: //创建一个对象猫,姓名为“妮妮”,毛色为“灰色”,年龄为2岁,在屏幕上输 //出该对象的毛色和年龄,让该对象调用显示姓名和喊叫两个方法. String name,color; int age; cat(String name,String color,int age) {