回首页 回首页 ◎ 设为首页  
◎ 收藏本站  
◎ 给我留言  
  
  首 页  C/C++教程  C++之父的FAQ  C/C++动向  C/C++源代码  C/C++误区  Unix/Linux  下载中心  乱七八糟  蚂蚁的Blog  
  当前位置:首 页 >> C/C++源代码 >> 数据结构与算法 C >> [转] 猴子吃桃问题的一种解答
最 近 更 新
[转] 猴子吃桃问题的一..
通讯录程序源代码推荐
快速排序
二路插入排序
[经典算法 C] 高斯分布..推荐
[数据结构 C]赫夫曼编码推荐
线索二叉树
二叉树的基本操作
银行业务模拟推荐
杨辉三角推荐
最 新 推 荐
通讯录程序源代码推荐
[经典算法 C] 高斯分布..推荐
[数据结构 C]赫夫曼编码推荐
银行业务模拟推荐
杨辉三角推荐
迷宫求解推荐
括弧匹配检验推荐
单链表的实现及其操作推荐
顺序表及其操作推荐
二进制转换十进制(顺序..推荐
热 门 排 行
通讯录程序源代码推荐
迷宫求解推荐
杨辉三角推荐
快速排序
银行业务模拟推荐
[转] 猴子吃桃问题的一..
[经典算法 C] 高斯分布..推荐
[数据结构 C]赫夫曼编码推荐
十进制转换八进制
二进制转换十进制(顺序..推荐
站 内 搜 索

Web stdcpp.cn
关键词

搜索方式

搜索范围

精确匹配
广 告

[转] 猴子吃桃问题的一种解答


来源:RobinWen的专栏 作者:我为C狂 等级:精品
发布于2006-01-30 22:25 被读6819次 【字体:

【问题描述】

    一只猴子在X天中一共吃了Y个桃子。已知这只猴子每天最多吃10个桃子,最少可以不吃桃子。问一共有多少种不同的吃法。
    例如:X=3,Y=4时(即3天吃4个桃子)一共有下面列出的15种不同吃法
        1         :0   0   4  
        2         :0   1   3  
        3         :0   2   2  
        4         :0   3   1  
        5         :0   4   0  
        6         :1   0   3  
        7         :1   1   2  
        8         :1   2   1  
        9         :1   3   0  
        10        :2   0   2  
        11        :2   1   1  
        12        :2   2   0  
        13        :3   0   1  
        14        :3   1   0  
        15        :4   0   0

  
【问题分析】

    这个题目比较好的解决方法是用递归。
    我们定义一个递归函数eat( x, y )表示在x天之内吃y个桃子。那么具体定义为:
    1、如果x=0且y=0,表示当前已经搜索到的是一种可行的解法,需要把该解法输出。
    2、如果x>0且y>0,表示还没有搜索完,那么就要按下面的方法继续递归:

           for ( i = 0 ; i <= 10 ; i++ )
               eat( x-1, y-i ) ;

这里的i相当于是该天吃桃子数量的探索值。但是由于可以在后面的几天里面一个桃子也不吃(见上面的5、9、12、14、15这几种情况),也就是说只要没有到最后一天(x=0),就需要继续向下搜索,所以x>0且y>0的条件是不完备的,应该是x>0且y>=0。
    3、其它情况(如x<0或y<0,x=0且y>0等)为非法情况或表明当前解不成立,故要返回。
    由此可以写出eat函数的伪代码:

        void eat( int x, int y )
        {
            if ( x > 0 && y >= 0 )
                for ( i = 0 ; i <= 10 ; i++ )
                    eat( x-1, y-i ) ;
            else if ( x == 0 && y == 0 )
                输出当前解;
            return ;
        }


【程序代码】

    根据上述思路,我们可以比较容易地写出下面的程序。不过,这里有几个地方经过了修改:
    1、为了便于结果的输出,所以使用了一个全局整型数组arr来存放当前解。
    2、为了便于对arr数组的下标进行管理,给eat函数增加一个参数idx,标识出当前的空余位置(把探索的解i放在该位置)。
    3、虽然每天最多吃10个桃子,但是如果当前情况下不够10个桃子,那么在进行for( i = 0 ; i <= 10 ; i++ )这个循环时,有些i值就是不必要的。所以程序设立了一个i_end变量,如果当前情况下剩余的桃子总数y多于10个,那么i_end取10;如果少于10个,那么就让i_end等于y。这样可以减少不必要的循环与递归。

    #include <stdio.h>

    #define DAY  3
    #define PEACH   4

    int arr[DAY] ;
    long int times ;
    FILE *fp ;

    void eat( int day, int peach, int idx )
    {
        if ( day > 0 && peach >= 0 )
        {
            int i, i_end ;

            i_end = ( (peach<10) ? (peach) : (10) ) ;
            for ( i = 0 ; i <= i_end ; i++ )
            {
                arr[idx] = i ;
                eat( day-1, peach-i, idx+1 ) ;
            }
            return ;
        }
        else if ( day == 0 && peach == 0 )
        {
            int i ;

            times++ ;
            fprintf( fp, "%-10ld:", times ) ;
            for ( i = 0 ; i < DAY ; i++ )
                fprintf( fp, "%-3d ", arr[i] ) ;
            fprintf( fp, "\n" ) ;

            return ;
        }
        else
            return ;
    }

    int main( void )
    {
        int day, peach ;

        day = DAY ;
        peach = PEACH ;
        times = 0 ;

        fp = fopen( "monkey.txt", "w" ) ; /* 打开用于保存结果的文件 */
        eat( day, peach, 0 ) ;
        fclose( fp ) ;                                  /* 关闭文件 */

        return( 0 ) ;
    }

本文乃网上搜集得来,其版权归原作者和原出处所有。如有侵犯版权之处请与我联系,我将马上进行处理。



相关专题:暂无相关专题

上一篇:通讯录程序源代码
下一篇:无相关文章

共有评论 13 条 网友评分 1分 查看全部评论

游客:styfwz
评分:0
这个算法很巧妙了.但是仍然有大量的计算冗余.如果用动态规划.效率会高很多
游客:Hunter
评分:0
使用三重循环看起来更容易理解,具体如下:
#include <stdio.h>

   int main (void)
   {
    int x,y,z,i=0;
    for(x=0;x<=4;++x)
       for(y=0;y<=4;++y)
          for(z=0;z<=4;++z)
             if(x+y+z==4)
             {
                 i=i+1;
             printf("%d %d %d %d\n",i,x,y,z);
            
             }         
            
    getchar();
   
    return 0;      
   }
游客:C菜鸟
评分:0
如果天数等于一个很大的数呢,那要循环多少次??
游客:c++参赛者
评分:3
题目中很多的细节是我在学校里看不到的,希望可以看到更多的信息。
游客:土豆
评分:0
我是个c++的初学者,花了将近一天的时间才把这个问题搞明白.嘿嘿,见笑了.下面使我在dev-c++里自己写的程序,其实思想跟楼主的一样.不过还是有好几个疑问,都在程序的注释里面.希望大家能教教我怎么解决.
#include<iostream>
using namespace std;

const int Days=3;/*1怎样才能手动输入天数和桃子呢? 2 变量名起的不好,注意大小写. */
const int Peachs=4;
int times=0;//用于记录这是第几种方案
int arr[Days];//记录解决方案
void eat(int days,int peachs,int idx);/*跟上面声明的Days,Peachs区别 */
int main()
{
    eat(Days,Peachs,0);
    system("pause");
    return 0;
}
/*下面这个算法很多无用的运算,以后考虑能不能改进下 .比如如果3天吃30个桃子只可能有1种情况,可下面就要每步都算. */
void eat(int days,int peachs,int idx)

{
     if(days>0&&peachs>=0)/*days应该是大于0而不是大于1.这样才能保证输入的是1天的时候也能正确处理*/
     {
         for(int i=0;i<=10;++i)
         {
            arr[idx]=i;
            /*核心部分.递归,思想就是将N天的问题转变诚N-1天.也就是说将2天的问题转化成1天. 这个idx变量很巧妙, 是我在网上学的.正是因为她,才能使数组arr
按顺序保存每天吃的桃子数 */
            eat(days-1,peachs-i,idx+1);
         }
     }
     
     else if(0==days&&peachs==0)/*输出部分只有当最后一天吃完了所有桃子才是正确的解决方案,才输出,如果不是,就跳过 */
           {
               cout<<++times<<":";
               for(int i=0;i<Days;++i)/注意,这里是大写的Days */
                   cout<<"   "<<arr[i];
               cout<<endl;
           }
     return ;
}
游客:土豆
评分:4
我觉得styfwz说得不对.当数量很大时用动态分配内存可以节省内存空间.但并不能减少冗余的运算啊!
游客:antigloss
评分:0
to 土豆:

1. 想手动输入的话,可以定义全局范围的 Days 和 Peaches 及 *arr

    int Days, Peaches, *arr;

然后在 main 函数中输入

    cin >> Days >> Peaches;

并且将 *arr 指向一段动态分配的内存空间

    arr = new int[Days];

当然,也有其它方法,不过这种相对容易实现。但是,这种方法的致命缺点是难以维护,容易出错。


2. 动态规划法是一种算法,并非指动态分配内存。你可以在网上搜索一下动态规划法的相关资料。
游客:土豆
评分:0
to antigloss
谢谢antigloss啊.按照你的方法我已经改进我的程序啦.实现了手动收入和动态分配数组.
不过实现手动输入的时候,因为没有了全局变量Days,Peachs和数组arr[Days].所以还是遇到了一些问题的.不过我自己都解决啦.^_^.不过我觉得在这里动态分配内存没什么必要.
我以前还以为动态规划法就是动态分配内存呢,丢人了.呵呵.以后有时间我去学习学习.
本来想把算法也改进一下的,排除一些特殊情况,比如3天吃30个桃子只有一种情况,3天吃20个以上桃子只有3种情况,可是涉及到递归,比较麻烦,越想越乱.
总之,今天学到了不少.受益匪浅

查看全部评论

【发表评论】 评分:1分 2分 3分 4分 5分


验证码:

Powered By Www.Xydw.COM Ver1.14 管理
Copyright © 2005-2006 蚂蚁的 C/C++ 标准编程 All Right Reserved. XCMS
粤ICP备06014124号   站长:Antigloss