黑马程序员学习笔记——过河问题

----------------------  ASP.Net+Unity开发 .Net培训 、期待与您交流! ----------------------

问题是:一位老农带着猫、狗、鱼过河,河边有一条船,每次老农只能带一只动物过河。当老农不和猫狗鱼在一起时,狗会咬猫,猫会吃鱼,当老农和猫狗鱼在一起时,则不会发生这种问题。编程解决猫狗鱼过河问题。
说一下主要思路吧,第一想法就是,程序自动判断

1.第一种思路,就是判读如果猫狗,或者鱼猫在一起,那就是不和谐状态,然后就来回倒腾,这个就不多说了
2.但如果想要扩展一下,什么叫扩展?扩展就是在不改变原有程序代码的情况下增加新的功能。
那我是这样处理的, 将这些动物都实现一个接口 ,这个接口中定义了一个自身是否能处于和谐的状态(无论是骚扰或是被骚扰,都是一种不和谐状态)。
这样的话,以后即使增加了一个新的物种,也只需额外判断它自己是否和谐就可以了,不会对原代码产生影响。

package interview.com;
/*
 * 这个是就是上面红字的核心思想
 */
public interface Animal {
	public void setBank(Bank b);
	public boolean isPeace();
}

package interview.com;
import java.util.Iterator;
/*
 * 猫类,主要属性有
 * 1.对应的主人
 * 2.在哪个岸上
 * 主要方法有,
 * 1.判断自己是否安全,2.设置去哪个岸
 */
public class Cat implements Animal {
	Bank nowBank = null;
	People host = null;
	public Cat(Bank nowBank, People host) {
		this.nowBank = nowBank;
		this.host = host;
	}
	//判断农夫是否在身边
	public boolean haveHost() {
		if (nowBank.equals(host.nowBank)) {
			return true;
		}
		return false;
	}
	
	//判断这个猫是否处于安全状态
	public boolean isPeace() {
		boolean haveHost = haveHost();
		//只有农夫不在的时候才不安全
		if (!haveHost) {
			Iterator it = nowBank.members.iterator();
			while (it.hasNext()) {
				//如果岸上有汪星人或者小鱼的话,就返回false
				Object o = it.next();
				if (o instanceof Dog || o instanceof Fish) {
					return false;
				}
			}
		}
		//如果农夫在或者没有鱼和汪星人,那就平安无事
		return true;
	}
	
	public String toString() {
		return "猫";
	}
	public void setBank(Bank b) {
		this.nowBank = b;
	}

}
狗和鱼同猫类,不贴了,看附件

package interview.com;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
 * 定义河岸,河岸具有保存动物的集合
 * 还具有判断动物们在一起是否能和平共处的方法
 */
public class Bank {
	//集合里的成员必须具备能够判断自身是否处于和谐状态的方法
	List<Animal> members = new ArrayList<Animal>();
	String str = null;
	public void addMember(Animal p) {
		members.add(p);
	}
	
	public Bank(){}
	public Bank(String str) {
		this.str = str;
	}
	
	public Animal getMember() {
		if (members.size() > 0) {
			return members.remove(0);
		}
		System.out.println("空了");
		return null;
	}
	
	public boolean isPeace(){
		Iterator<Animal> it = members.iterator();
		while (it.hasNext()) {
			//如果集合里有一个物种是存于不和平状态,那就就是不和平
			if (!it.next().isPeace()) {
				return false;
			}
		}
		//只有大家都和平,才是真和谐,这时才返回true
		return true;
	}
	
	public String toString() {
		return str;
	}
	
}
package interview.com;
/*
 * 人类,这个其实是我主功能实现类了
 * 因为人永远和船是方向一致的,所以我直接把船给省略了
 * 人的主要方法:
 * 1.取动物的方法
 * 2.将取来的动物放到对岸的方法
 */
public class People {
	Bank leftBank = null;
	Bank rightBank = null;
	Bank nowBank = null; //判断人在哪个岸上
	Bank lastBank = null; //最后一次离开的是哪个岸
	
	
	public People(Bank leftBank, Bank rightBank) {
		this.leftBank = leftBank;
		this.rightBank = rightBank;
		nowBank = leftBank;
	}
	
	//带走一个可以使这边和谐的物种
	public void takeAnimal() {
		//岸上的动物每个都尝试一遍可不可以带走
		for (int i=0; i<nowBank.members.size(); i++) {
			Animal p = nowBank.getMember(); //把集合的第一个动物拿走
			
			lastBank = nowBank;
			nowBank = null;//假装上船看看离开后是否安全
			if (lastBank.isPeace()) {
				nowBank = lastBank;//如果安全就正式起航
				System.out.println("---农夫把"+p+"从"+nowBank+"带去了对岸");
				toOpposite();
				p.setBank(nowBank);
				dropAnimal(p);
			} else {
				nowBank = lastBank;//如果不安全就重新回到岸上
				nowBank.addMember(p);
			}
		}
		System.out.println("农夫仰天长叹,无解啊"); //全部尝试结束,还是没找到合适的方案
//		return null;
	}
	
	public void dropAnimal(Animal p) {
		if (p != null) {
			nowBank.addMember(p);
			System.out.println("现在左岸有"+leftBank.members+",右岸有"+rightBank.members);
		}
		if (nowBank == rightBank) {
			if (nowBank.members.size() == 3) {
				System.out.print("运输完成 ");
				System.exit(0);
			}
			lastBank = nowBank;
			nowBank = null;
			if (lastBank.isPeace()) {
				nowBank = lastBank;//如果安全就空船返回
				toOpposite();
				System.out.println("空船返回左岸");
				takeAnimal();
			} else {
				nowBank = lastBank;
				takeAnimal(); //如果不安全就捎一个回去
			}
		}
		takeAnimal(); //如果这个是从右岸捎回来的话,就继续正常运输
	}

	public void toOpposite() {
		if (nowBank == leftBank) {
			lastBank = leftBank;
			nowBank = rightBank;
		} else if (nowBank == rightBank) {
			lastBank = rightBank;
			nowBank = leftBank;
		}
	}
}
下面是主运行类:

package interview.com;

import java.util.Collections;

/*
 * 这个就是主函数了,主要是生产动物,老农 
 * 然后运行
 */
public class Transport {
	public static void main(String[] args) {
		//目标是把左岸的运到右岸去
		Bank left = new Bank("左岸");
		Bank right = new Bank("右岸");
		People farmer = new People(left, right);
		Fish fish = new Fish(left, farmer);
		Dog dog = new Dog(left, farmer);
		Cat cat = new Cat(left, farmer);
		
		left.addMember(dog);
		left.addMember(fish);
		left.addMember(cat);
		Collections.shuffle(left.members);//打乱一下顺序,一般打印可能存在的多种情况
		
		farmer.takeAnimal();
	}
}


分析一下程序的不足:

主要是不足在这个地方:
比如说有好多物种,判断条件很复杂,这时就会出现这种现象:先把A物种弄到对岸,相安无事,然后把B物种弄到对岸,还是相安无事,
但这个,第三趟把C物种弄到对岸后,发现程序无解了,这时候就需要返回到原来的初始状态重新开始,
也就是说,你每一步都需要记录一个状态,当发现下一步无法进行时,就需要恢复这个状态,当这个状态下所有情况都无法满足条件时,你需要恢复再之前的状态。
你跟走象棋悔棋一样,有时候你需要悔好几步才能达到理想状态。

附件链接:http://download.csdn.net/detail/u013765450/7230725


---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值