/**
*10、 一位老农带着猫、狗、鱼过河,河边有一条船,每次老农只能带一只动物过河。
*当老农不和猫狗鱼在一起时,狗会咬猫,猫会吃鱼,当老农和猫狗鱼在一起时,则不会发生这种问题。
*编程解决猫狗鱼过河问题。
*
*分析:
* 问题中的对象:猫、狗、鱼、老农、岸1(这岸)、岸2(对岸)
*
*
* 限制条件是:老农每次只能带一只动物过河
* 老农不在时,狗咬猫
* 老农不在时,猫吃鱼
* 目标是:将猫、狗、鱼从这岸运到对岸。
* 当农夫到达一个岸后,即为一个中间状态,则这个中间状态需要满足,岸1,岸2都是安全的
*
* 初始输入:是岸1中有3个对象,老农处在岸1
*
* 结果输出:将岸1中的对象移动到岸2中的具体步骤
*
* 岸1、岸2:可以添加不同类的对象,所以内部是一个集合,同时岸上是否有冲突,岸清楚,所以岸中有检测方法。
* 他们属于同一个类。对于具体要运送哪个对象才是合适的(即运送后岸是安全的),岸最清楚,所以要有
* 运送方法。
*
* 猫、狗、鱼:虽然是不同类,但是有共性,那就是他们可能有自己的天敌(也有可能没有),所以要有获取天敌的方法。
* 还有就是他们是否是安全的,所以有两个方法。
* 他们属于不同类,而检测是否安全的方法代码完全相同,所以定义一个抽象类来被他们继承。
*
* 老农:有两个方法,一个是自己过河,一个是运送动物过河。如何运送一个具体动物过河,以及运送该动物成功与否,
* 老农自己最清楚,老农是一个单独的类
*
* 审题结果:这个问题重在练习面向对象的思想和对象的设计,以及问题的分析能力,这个问题并不具备太强的
* 可扩展性,如果扩展大了,那么问题就改变了,不再是同类型的问题了。这是个A->B->C,有向图,且要首先
* 带走度为2的节点B,如果出现两个以上的度为2的节点,这个问题就无解了,如果出现一个度为3或者3以上的节点
* ,也是无解的。
*
*思路:
*
*1,定义 岸、猫、狗、鱼、老农 5个类
*2,老农运送 岸1中的一只动物到岸2,如果岸1处于和谐状态,则运送这只动物,否则换另一只动物。
*3,老农到达岸2后,检查岸2是否和谐,和谐,则自己离开,到2,否则运送一只动物离开,使其和谐,再到2
*4,全部运送完后,岸1空结束。
*
*(为使得代码尽量简洁,就不自定义hashCode,equals方法,程序中没有用到,但如果实际项目的话,需要进行
*覆盖。)
*/
package com.itheima;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//定义一个抽象类Animal,表示动物必须实现的方法,以及必须具备的功能
abstract class Animal
{
//每个动物都必须具备这项功能,即判断自己在给定的Bank下是否是安全的
public boolean isSafe(Bank bank) {
// TODO Auto-generated method stub
return !(bank.containsClass(naturalEnemy())); //如果给定bank中天敌存在,则不安全,否则安全
}
//让子类去实现的方法,每个子类都要定义自己的天敌,并通过该方法返回
public abstract String naturalEnemy();
}
//定义Bank类,表示“岸”这类事物
class Bank
{
//定义Bank的名字,方便打印输出
private String name = null;
//定义容器,用来存储将要加进来的动物对象
private Map<String, Object> map = new HashMap<String,Object>();
//定义当前出现安全问题的动物
private Animal currentProblem = null;
//创建对象的时候,就指定岸对象的名字
Bank(String name)
{
this.name = name;
}
@Override//覆盖toString方法
public String toString()
{
return name;
}
//定义岸的添加动物对象的方法
void add(Object obj)
{
map.put(obj.getClass().getName(), obj); //调用容器的相应添加方法
}
//定义岸的删除对象的方法,并返回删除的对象
Object delete(Object obj)
{
return map.remove(obj.getClass().getName()); //调用容器的相应删除方法
}
//定义方法用来判断一种动物在该岸中是否存在
boolean containsClass(String className)
{
return map.containsKey(className);
}
//打印Bank中的动物对象
void printBank()
{
System.out.print(this+" : ");
Set<Map.Entry<String,Object>> entrys = map.entrySet();//获取Map集合中的所有条目的Set集合
//打印Bank中封装map容器中的内容,
for(Map.Entry<String, Object> entry : entrys)
{
Animal obj = (Animal)entry.getValue();
System.out.print(obj+" "); //用空格分隔每个动物对象
}
System.out.println();
}
//判断岸的当前状态是否是安全的,即动物们是否是和谐相处的
boolean isSafe()
{
boolean flag = true;
Set<Map.Entry<String,Object>> entrys = map.entrySet();//获取Map集合中的所有条目的Set集合
//循环判断每个动物是否是安全,如果每个动物都是安全的,那么岸就是安全的,否则岸就是不安全的
for(Map.Entry<String, Object> entry : entrys)
{
String className = entry.getKey();
Animal obj = (Animal)entry.getValue();
if(!obj.isSafe(this)){ //判断动物在当前岸的状态下是否是安全的
flag = false;
currentProblem = obj; //如果不安全,则记录当前处于不安全状态的那个对象
break;
}
}
return flag; //返回结果
}
//定义方法供当前岸对象,指挥farmer,将自己的一个对象运送到对岸,也即bank
boolean transport(Farmer farmer,Bank bank)
{
boolean flag = false;//初始设置为运送失败
Map<String, Object> mapTemp = new HashMap<String,Object>(map);//拷贝副本,用来遍历
//获取当前bank中目前有的对象
Set<Map.Entry<String,Object>> entrys = mapTemp.entrySet();
for(Map.Entry<String, Object> entry : entrys) //运送一个对象到bank,直到成功为止
{
Animal obj = (Animal)entry.getValue();//取得一个具体的对象
//指挥farmer将obj从当前岸(this)运送到彼岸(bank)
if(farmer.transport(obj,this,bank))
{
flag = true;
System.out.println("将 \""+obj+"\" 从 "+this+" 运送到 "+bank); //如果运送成功,则打印
break;
}
}
return flag;
}
//定义方法,用来判断当前岸是否是空的状态,即当前岸中一个动物也没有
boolean isEmpty()
{
return (map.size() == 0);
}
}
//定义猫子类,继承父类Animal
class Cat extends Animal
{
//实现抽象方法,定义自己的天敌
public String naturalEnemy() {
// TODO Auto-generated method stub
return "com.itheima.Dog"; //将天敌的类型返回
}
@Override //覆盖toString方法,方便打印
public String toString()
{
return "猫";
}
}
//定义狗子类,继承父类Animal
class Dog extends Animal
{
//实现抽象方法,定义自己的天敌
public String naturalEnemy() {
// TODO Auto-generated method stub
return "null"; //将天敌的类型返回,狗没有天敌,用"null"字符串表示没有天敌
}
@Override //覆盖toString方法,方便打印
public String toString()
{
return "狗";
}
}
//定义狗子类,继承父类Animal
class Fish extends Animal
{
//实现抽象方法,定义自己的天敌
public String naturalEnemy() {
// TODO Auto-generated method stub
return "com.itheima.Cat"; //将天敌的类型返回
}
@Override //覆盖toString方法,方便打印
public String toString()
{
return "鱼";
}
}
//定义农夫类
class Farmer
{
//定义属性animal,用来记录上一次运送的对象,防止死循环
private Animal animal = null;
//定义属性bank,用来表示农夫现在所处的位置是哪个岸
private Bank bank = null;
//初始化时,指定farmer位于那个岸,即哪个bank
Farmer(Bank bank)
{
this.bank = bank;
}
//农夫只将自己运送到指定的岸bank
boolean transport(Bank bank)
{
this.bank = bank;
return true;
}
//farmer将指定对象obj,从bank1运送到bank2
boolean transport(Object obj,Bank bank1,Bank bank2)
{
this.bank = bank2; //farmer即将划船到bank2
//obj刚刚才运过,刚从bank2运送到bank1,所以不能再从bank1运送到bank2了
if(animal == obj)
return false; //直接返回运送失败
//开始运送obj,现将其从bank1中删除
animal = (Animal)bank1.delete(obj);
//看看bank1是否是安全的
if(bank1.isSafe())
{
bank2.add(obj); //bank1安全,将obj运送到bank2,即添加进bank2
return true;
}
else //bank1不是安全的,运送失败
{
bank1.add(obj); //运送失败,将obj添加回bank1
return false; //返回运送失败
}
}
@Override //覆盖toString方法,方便打印
public String toString()
{
return "农夫";
}
//打印农夫现在位于哪个岸
void printBank()
{
System.out.println(this+" 位于 "+bank);
}
}
//测试类
public class Test10 {
//用于打印问题的初始情况
public static void initSituation(Farmer farmer ,Bank bank1,Bank bank2)
{
System.out.println("初始情况:");
bank1.printBank();
bank2.printBank();
farmer.printBank();
System.out.println("-------------------------------------");
}
//用于打印问题的最终情况
public static void endSituation(Farmer farmer ,Bank bank1,Bank bank2)
{
System.out.println("-------------------------------------");
System.out.println("最终情况:");
bank1.printBank();
bank2.printBank();
farmer.printBank();
}
//main函数
public static void main(String[] args) {
//创建bank1,bank2
Bank bank1 = new Bank("岸A");
Bank bank2 = new Bank("岸B");
//将猫、狗、鱼添加到bank1中
bank1.add(new Dog());
bank1.add(new Cat());
bank1.add(new Fish());
//创建农夫对象farmer
Farmer farmer = new Farmer(bank1);
//打印问题的初始情况
initSituation(farmer, bank1, bank2);
//一直运送直到bank1岸为空
while(!bank1.isEmpty())
{
//bank1不为空,则从bank1运送一个对象到bank2
if(bank1.transport(farmer, bank2))
{
//运送完一次,立即判断bank1是否为空,如果为空,则完成目标,跳出循环,结束
if(bank1.isEmpty())
break;
//如果bank1运送成功,则农夫从bank2返回到bank1,并检查bank2当前是否安全,由此决定以何种
//方式返回到bank1,是只运送自己,还是再从bank2中带走一个对象到bank1
if(bank2.isSafe())
{
System.out.println("\""+farmer+"\""+" 自己一个人从 "+bank2+" 划船到 "+bank1); //如果运送成功,则打印
farmer.transport(bank1);//bank2安全,只运送自己到bank1
}
else
{
bank2.transport(farmer,bank1);//bank2不安全,需要带走bank2中的一个对象到bank1
}
}
else
{
System.out.println("对于这个问题,暂时无解");//针对于这个具体的问题,出现这种情况意味着无解
}
}
//打印问题的最终情况
endSituation(farmer, bank1, bank2);
}
}
原文:http://www.cnblogs.com/wllbelief-win/p/4437885.html