黑马程序员技术交流社区

标题: 黑马程序员自学第一天,经典猴子吃桃的问题! [打印本页]

作者: wssjdysf    时间: 2013-10-29 01:46
标题: 黑马程序员自学第一天,经典猴子吃桃的问题!
---------------------- <a target="blank">ASP.Net+Android+IOS开发</a>、<a target="blank">.Net培训</a>、期待与您交流! ----------------------


package time20131028;

/**
* MonkeysEatAPeach(猴子吃桃)
* 需求:猴子吃桃的问题:猴子第一天摘下来N个桃子,当天就吃了一半,但是还不过瘾,又多吃了一个,第二天早上
* 又将剩下的桃子吃了一半,又多吃了一个,以后每天早上都吃了前一天剩下的一半零一个,到第十天早上的时候
* 就发现剩下一个桃子了.求第一天一共摘下了多少桃子呢?
* @author Terry
* 2013-10-23
*
*/
public class MonkeysEatAPeach {

        /**
         * @param args
         */
        public static void main(String[] args) {
                // TODO Auto-generated method stub
//                下面注释是留下来做对比的(未用面向对象思想设计,做下来发现方法需要返回2个int类型的值,就知道要用面向对象来做了,在这次的
//                对比之下让我对面向对象的体会有所提高)
//                /*
//                 * n:一共多少桃子,day:吃了多少天,surplus:最后剩余多少个桃子;
//                 */
                int n = 1000;int day;int surplus;
                day = 9;//到第十天早上的时候就发现剩下一个桃子了,所以得出桃子一共吃了9天;
                surplus = 1;//就发现剩下一个桃子了,所以surplus=1;
                eatPeach(n);
               
               
                CounterOfMonkeysEatAPeach counter = new CounterOfMonkeysEatAPeach();
                counter.setPeachesEatDay(1);
                counter.setPeachesSurplus(1);
                counter.setPeachesEatedDay(10);
                /**
                 * 反向理解猴子吃桃子
                 */
                eatPeach2(counter);
                counter.setPeachesSum(counter.getPeachesSurplus());
                System.out.println("猴子第一天摘了\""+counter.getPeachesSum()+"\"个桃子!");
                /**
                 * 正向理解猴子吃桃子
                 */
            counter.setPeachesSumByFirstDay(1534);
            counter.setPeachesSum(1534);
                counter.setPeachesSurplus(1);
                counter.setPeachesEatDay(0);//设置天数的初始值
                counter.setPeachesEatedDay(10);
                eatPeach1(counter);
        }
//        下面是留下来做对比用的
        /**
         * 正向理解猴子吃桃子的问题,得出的方法(此方法是在得知一共有多少个桃子的情况下设计出来的)未用面向对象设计,做到后面就做不下
         * 去了,转用面向对象的设计做的
         * @param surplus剩余多少个桃子
         * @return
         */
        private static int eatPeach(int surplus){
                if(surplus > 1){
                        surplus =surplus - (surplus/2 + 1);
                        //System.out.println(surplus);
                        eatPeach(surplus);
                        return surplus;
                }
                return surplus;
        }
       
       
       
        /**
         * 正向理解猴子吃桃子的问题,得出的方法(此方法是在得知一共有多少个桃子的情况下设计出来的,与题意思相符)
         * 有运用递归算法:直白的说,就是方法自己调用自己。
         * 经过测试此方法是正确的
         * @param surplus剩余多少个桃子
         * @return
         */
        private static CounterOfMonkeysEatAPeach eatPeach1(CounterOfMonkeysEatAPeach counter){
                int peachesSum = counter.getPeachesSum();
                if(peachesSum > counter.getPeachesSurplus()){
                        counter.setPeachesSum(peachesSum - (peachesSum/2 + 1));
                        counter.setPeachesEatDay(counter.getPeachesEatDay() + 1);
                        System.out.println(counter.getPeachesEatDay());
                        eatPeach1(counter);
                        return counter;
                }
                System.out.println("有\"" + counter.getPeachesSumByFirstDay() + "\"个桃子,猴子一共吃了\"" +
                counter.getPeachesEatedDay() + "\"天,还剩余\"" + counter.getPeachesSurplus() + "\"个桃子!");
                return counter;
        }
       
        /**
         * 反向理解猴子吃桃子的问题,得出的方法(此方法是在不知道一共有多少个桃子的情况下设计出来的,与题意思不相符)
         * @param surplus剩余多少个桃子
         * @return
         */
        private static CounterOfMonkeysEatAPeach eatPeach2(CounterOfMonkeysEatAPeach counter){
                //counter.setPeachesEatDay(counter.getPeachesEatDay() + 1);//位子不对,还没吃就加了一天不符合逻辑
                int peachesSurplus = counter.getPeachesSurplus();
                int eatDay = counter.getPeachesEatDay();
                if(eatDay < counter.getPeachesEatedDay()){
                        //counter.setPeachesSurplus(peachesSurplus + (peachesSurplus * 2 - 1));//吃桃子流程,错误1
                        //counter.setPeachesSurplus(peachesSurplus + 2 * (peachesSurplus - 1));//吃桃子流程,错误2
                        //counter.setPeachesSum(peachesSum - (peachesSum/2 + 1));//正向思维,正确,用来与下面一行做对比思考
                        /**
                         * 正向:当天就吃了一半,但是还不过瘾,又多吃了一个。(m - (m / 2 + 1))
                         * 反向:猴子先吐出一个,然后再吐出剩余的一半。((m + 1) * 2)
                         * ((m + 1) * 2)这是重点
                         */
                        counter.setPeachesSurplus( 2 * (peachesSurplus + 1));//吃桃子流程
                        System.out.println(counter.getPeachesSurplus());
                        counter.setPeachesEatDay(counter.getPeachesEatDay() + 1);//天数加一天
                        eatPeach2(counter);
                        return counter;
                }
                return counter;
        }
}



/**
* CounterOfMonkeysEatAPeach(直译:计数器的猴子吃桃子。正译:猴子吃桃的计数器。)
*
* @author Terry
* 2013-10-23
*
*/
class CounterOfMonkeysEatAPeach{
        /**
         * 一共有多少桃子
         */
        private int peachesSum;
        /**
         * 还剩余多少桃子
         */
        private int peachesSurplus;
        /**
         * 第几天吃桃子
         */
        private int peachesEatDay;
        /**
         * 桃子吃了几天
         */
        private int peachesEatedDay;
        /**
         * 第一天一共有多少桃子
         */
        private int peachesSumByFirstDay;
        /**
         * 得到桃子的总和
         * @return peachesSum:桃子总和
         */
        public int getPeachesSum() {
                return peachesSum;
        }
        /**
         * 设置桃子的总和
         * @param peachesSum:桃子总和
         */
        public void setPeachesSum(int peachesSum) {
                this.peachesSum = peachesSum;
        }
        /**
         * 得到桃子的剩余
         * @return peachesSurplus:桃子剩余
         */
        public int getPeachesSurplus() {
                return peachesSurplus;
        }
        /**
         * 设置桃子的剩余
         * @param peachesSurplus:桃子剩余
         */
        public void setPeachesSurplus(int peachesSurplus) {
                this.peachesSurplus = peachesSurplus;
        }
        /**
         * 得到第几天吃桃子
         * @return peachesEatDay:第几天吃桃子
         */
        public int getPeachesEatDay() {
                return peachesEatDay;
        }
        /**
         * 设置第几天吃桃子
         * @param peachesEatDay:第几天吃桃子
         */
        public void setPeachesEatDay(int peachesEatDay) {
                this.peachesEatDay = peachesEatDay;
        }
        /**
         * 得到桃子吃了几天
         * @return peachesEatedDay:桃子吃了几天
         */
        public int getPeachesEatedDay() {
                return peachesEatedDay;
        }
        /**
         * 设置桃子吃了几天
         * @param peachesEatedDay 桃子吃了几天
         */
        public void setPeachesEatedDay(int peachesEatedDay) {
                this.peachesEatedDay = peachesEatedDay;
        }
        /**
         * 得到第一天的桃子总和数
         * @return peachesSumByFirstDay 第一天的桃子总和数
         */
        public int getPeachesSumByFirstDay() {
                return peachesSumByFirstDay;
        }
        /**
         * 设置第一天的桃子总和数
         * @param peachesSumByFirstDay 第一天的桃子总和数
         */
        public void setPeachesSumByFirstDay(int peachesSumByFirstDay) {
                this.peachesSumByFirstDay = peachesSumByFirstDay;
        }
}


---------------------- <a target="blank">ASP.Net+Android+IOS开发</a>、<a target="blank">.Net培训</a>、期待与您交流! ----------------------



第一次发这种帖子,希望大家能看懂。有什么不好的地方,希望大家都指出来哈。
作者: doitforyou    时间: 2013-10-29 12:23
代码可读性太差了,读起来感觉很乱很累。不过面向对象的思想很好。我因为对这个感兴趣些才看了下去。
有一个最容易迷惑人的一点:
* 正向:当天就吃了一半,但是还不过瘾,又多吃了一个。(m - (m / 2 + 1))
* 反向:猴子先吐出一个,然后再吐出剩余的一半。((m + 1) * 2)
上面是你的代码,两个m意思不一样,易产生误解,尤其是第二个的文字注解,很容易让人感觉m是吐出的另一半,实际它应该是当天剩下的桃子。

其实感觉算法和逻辑思维才是王道,这点也是我的软肋。如这个题目,如果逻辑思维强的话,逆向思维,将最后一天当做第一天,设置桃子为变量x=1;
然后循环9天只需要一个循环就搞定了。
for(i=0; i<9; i++)
{
    x= 2*(x+1);
}
结果为1534。
作者: wssjdysf    时间: 2013-10-29 21:28
谢谢楼上的师兄指出的问题,关于你说的问题以后我会修改的!!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2