A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 世界公民   /  2014-4-20 06:47  /  15240 人查看  /  40 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

[code]package com.itheima;

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

/*
* 题目10:10、 一位老农带着猫、狗、鱼过河,河边有一条船,每次老农只能带一只动物过河。
*                                当老农不和猫狗鱼在一起时,狗会咬猫,猫会吃鱼,当老农和猫狗鱼在一起时,则不会发生这种问题。
*                编程解决猫狗鱼过河问题。
*      
* 分析思路: 在纸上分析过后得知要像将猫、狗、鱼安全的送往河对岸,可使用下述步骤:
*                    第一步:将猫先运到河对岸 ,放下猫农夫和船回来;           ====> 已过河: 猫
*                    第二步:将狗装上船运到河对岸,并且将猫带回放下;        ====> 已过河: 狗
*                    第三步:将鱼运过对岸放下,农夫空船回来;                        ====> 已过河: 狗、鱼
*                    第四步:农夫将猫再次运到河对岸。                                        ====> 已过河: 狗、鱼、猫
*/
public class Test10 {

        // 1:因为数据长度频繁的改变所以,用集合来装数据。并且将河的两边比喻为两个不同的集合
        // left :表示左边的河岸 right:表示右边的河岸也就是对岸。
         List<String> left = new ArrayList<String>();
         List<String> right = new ArrayList<String>();

        // 2:因为一开始河的左岸就是有人和三个动物的,所以程序一加载就应该添加他们
        public Test10() {
                left.add("farmers");
                left.add("cat");
                left.add("dog");
                left.add("fish");
        }

        public static void main(String[] args) {
                // 调用过河方法
                Test10 test = new Test10();
                /*for (String string : test.left) {
                        System.out.println(string);
                }*/
                test.passRiver();
        }

        // 过河的方法
        public void passRiver() {
                do {
                        // 首先农夫上船
                        left.remove("farmers");

                        // 接着农夫随便的带上一只动物上船,利用脚标取值,脚标随机并且在[1,4)之间,对应 cat、dog、fish
                        // 产生随机数,可以使用Random类中的nextInt(int num);方法产生一个在[0,num)之间的数
                        int leftIndex = new Random().nextInt(left.size());  /*IllegalArgumentException:抛出的异常表明向方法传递了一个不合法或不正确的参数。*/
                        
                        // 取得脚标所对应的动物,并装上船
                        String animal = left.get(leftIndex); /*IndexOutOfBoundsException:脚标越界*/
                        
                        //判断农夫现在带走的动物是否是上一次带回来的动物(因为每次都会自动的添加到最后一个)
                        if (left.size()>1 && animal.equals(left.get(left.size()-1))) {
                                left.add("farmers");
                                //跳出当前循环,进入下一个循环
                                continue;
                        }
                        left.remove(animal);

                        // 此时left的岸边只有两个动物了,并且我们不确定这两个其中是否有猫,所以得判断
                        if (isSafe(left)) {
                                // 将左边的动物带到河对岸。
                                right.add(animal);
                                System.out.println("恭喜农夫和"+"\'"+animal+"\'"+"成功渡河!");
                                // 此时如果河对岸有3个动物,并且不包括农夫的话就算过河都成功返回
                                if (right.size() == 3 && !right.contains("farmers")) {
                                        System.out.println("恭喜狗、猫、鱼渡河成功!!!");
                                        break;
                                }

                                // 此时农夫准备返航回去,那么就得判断农夫离开后河对岸(right)是否安全
                                // 但是如果对岸只有一个动物的话就没有必要判断了
                                if (right.size() != 1) {
                                        if (isSafe(right)) {
                                                left.add("farmers");
                                                System.out.println("农夫独自返航了!");
                                        } else {
                                                // 获取对岸动物的脚标
                                                int rightIndex = new Random().nextInt(right.size());
                                                // 获取脚标对应的动物名
                                                String animal2 = right.get(rightIndex);
                                                // 如果不安全,则要带回一个动物,但是不能是前一次带过来的动物。
                                                while (animal2.equals(animal)) {
                                                        animal2 = right.get(rightIndex);
                                                }
                                                //将非上一次带过来的动物从对岸带回
                                                right.remove(animal2);
                                                left.add(animal2);

                                                System.out.println("农夫和" + "\'" + animal2 + "\'回来了");

                                        }
                                } else {
                                        left.add("farmers");
                                        System.out.println("农夫独自返航了!");
                                }

                        } else {
                                // left岸边的动物们不安全,把带上的动物放下换一个
                                left.add("farmers");
                                left.add(animal);
                        }

                } while (left.size() != 0);
        }

        // 判断是否安全的方法,返回的是boolean类型的值
        private static Boolean isSafe(List<String> list) {
                // 定义一个变量用来接收返回的值
                Boolean flag;

                // 判断两边岸的动物是否安全的依据是看猫和农夫是否在一起,如果农夫和猫不在一起并且猫和其他的动物在一起,则河岸不安全。
                if (list.size() > 1 && list.contains("cat") && list.contains("cat")
                                || list.contains("cat") && list.contains("fish")) {
                        flag = false;
                } else {
                        flag = true;
                }

                return flag;
        }

}
[/code]
回复 使用道具 举报
这题我头疼
回复 使用道具 举报
sanguodouble1 发表于 2014-4-20 11:24
这个问题很有意思,先说下我的思路吧,代码有空再写
我觉得,关键是以程序的方法去实现,也就是让程序自动 ...

    哥们,这个问题,你就不要人为的复杂化了,也不要求一个通用解,如果非要求一个通用解,那么只是适合于A,B,C这种模式,也即狗、猫、鱼。
    这个问题抽象出来后和你举得那个扩展例子抽象出来后不是一个类型的问题,好比x2和x3的方程的解决方法和解决需要的条件不同一样,看似类似,实则不同。
    猫狗鱼问题抽象出来后,是"A->B->C",这个模式的问题,优先运走,度为2的对象(即B),而且这个有向图中不允许存在两个度为2的对象,也不允许存在度为3的对象,这个度包括出度和入度。否则,就是无解。
所以,这个问题主要是用来锻炼大家的对象抽取能力和设计能力,以及问题的分析能里。
      
     这个不是一个可以扩展的问题,要扩展也只能扩展成(A->B->C   D->E->F),你的扩展就属于另一个问题,不属于和原问题同类型的问题了。用到的东西可能会更多,问题难度要大很多。3个的可能只是一个特例。这个就好比2重积分可以看成是3重积分的一个特例一样,但是3重积分的解法是更复杂的问题。
     最后,真想扩展,那你也要先固定好到底是几个对象,几个约束条件,几个可以渡河运送人的等等,不固定,就谈不上问题的通解,尤其使用程序来做这件事,也许数学还可以有通解。
回复 使用道具 举报
另外,这个问题可以谈对象抽取和方法封装的设计,谈类的设计,至于算法的高效,到底用广搜和深搜,还是自动机,动态规划,又是状态之类的,其实没有太大意思。这是个较为特殊的特例问题,而且解决方案也较为单一的问题,不是什么需要大优化之类的问题规模很大的问题。
回复 使用道具 举报
高手啊
回复 使用道具 举报
Melo 中级黑马 2015-5-21 22:11:40
26#
这题知道怎么过 可是一到代码上就懵圏了
回复 使用道具 举报
我是来学习的。。
回复 使用道具 举报
呆呆沙师妹 发表于 2014-4-20 13:51
我也碰上过这个题。想了好久才做出来。
在这里也分享一下自己的思路,期待有更好的算法。
...

你的实现不了,只要把集合中鱼的位置排到第一位,你循环几千次都出不来
回复 使用道具 举报
我也正在写这道题!!
回复 使用道具 举报
很不错,是大神
回复 使用道具 举报
关度飞 发表于 2014-8-11 00:51
嗯嗒 正在写这道题

刚看到你写的时间,话说你现在工作多久了?感觉怎么样呢
回复 使用道具 举报
逻辑最简单了,算法怎么才能最好呢
回复 使用道具 举报
看了好几天了
回复 使用道具 举报
都是面向对象的思想,,难道社招的难度大那么多?
回复 使用道具 举报
呆呆沙师妹 发表于 2014-4-20 13:51
我也碰上过这个题。想了好久才做出来。
在这里也分享一下自己的思路,期待有更好的算法。
...

真心点赞,写不出来
回复 使用道具 举报
楼主成功运行了吗,我怎么在自己的电脑上变异不上呢
回复 使用道具 举报
呆呆沙师妹 发表于 2014-4-20 13:51
我也碰上过这个题。想了好久才做出来。
在这里也分享一下自己的思路,期待有更好的算法。
...

写的很好,不过有一个地方有Bug,
if( lossAnimal(left) ){
    left.add( animal );
    continue;
}

把动物remove()以后,再添加时,如果不加用添加的位置,就会默认放在后面,这样在遍历时就出现了Bug
回复 使用道具 举报
第一步:把猫带过去;
第二步:农夫回来把鱼(狗)带过去;
第三步:农夫回来的时候把猫带回来再把狗(鱼)带过去;
第四步:农夫在回来把猫带过去。
回复 使用道具 举报
学习学习
回复 使用道具 举报
sanguodouble1 发表于 2014-4-20 11:24
这个问题很有意思,先说下我的思路吧,代码有空再写
我觉得,关键是以程序的方法去实现,也就是让程序自动 ...

这样一份感觉思路清晰多了
回复 使用道具 举报
12
您需要登录后才可以回帖 登录 | 加入黑马