放鸡蛋问题

原创 2016年08月30日 23:35:20

我们先来看看题目:

Erin买了不少鸡蛋,她发现一天吃不完这么多,于是决定把n个同样的鸡蛋放在m个同样的篮子里,允许有的篮子空着不放,请问共有多少种不同的放法呢?
注意:2,1,1和1,2,1 是同一种分法。

Input 第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数m和n,以空格分开。1<=m,n<=10。

Output 对输入的每组数据m和n,用一行输出相应的结果。

例如:

Input:

4

3 8

4 7

2 4

4 2

Output:

10

11

3

2

(注意结尾有换行)

第一次接触这种题目,大家最头疼的应该是例如(1, 2, 1)和(1, 1, 2)一样的重复问题,如何解决重复问题,是该题的一大难点。

我说说我的思路。

根据题意我们可以大概分成三种情况:鸡蛋数目多于篮子数目,鸡蛋数目等于篮子数目,鸡蛋数目少于篮子数目。

首先,我们来看看最简单的一种情况:鸡蛋数目少于篮子数目。

很明显,鸡蛋少的时候就算每个篮子都放一个鸡蛋,必定会有篮子放不满,因此我们很容易就可以将这种情况简化成为:将n个鸡蛋放入m个篮子(n <m)。

然后,我们再来看看另外一种情况:鸡蛋数目多于篮子数目

鸡蛋数目多于篮子数目时,很显然每个篮子都可以放满,当然也可以只有一个篮子放满,但是再放鸡蛋的过程中,很容易发生重复的情况,这时候我们不妨这样思考:

假设共有M个篮子,N个鸡蛋。现在我们先假设M个篮子都放满且每个篮子都只放一个鸡蛋,放入鸡蛋后剩下的鸡蛋数目为N-M,再让剩下的N-M去放M个篮子,此时我们不继续往下讨论。再假设M-1个篮子都只放满一个鸡蛋,与前面同样的道理,我们可以得到让N-(M-1)个鸡蛋放M-1个篮子……这样一个个增加空篮子的数目直到非篮子数目为2或1。

为了更清楚地说明这种原理,我们设一个放鸡蛋函数为f(M, N) (M为篮子数目,N为鸡蛋数目),然后我们引用例子中M= 4, N= 7,我们就可以进行拆分:

f(4,7)= f(4, 3)+f(3, 4)+f(2, 5)+f(1, 6)
= [f(3, 3)]+[f(3, 1)+f(2, 2)+f(1, 3)]+[f(1, 4)+f(2, 3)]+[f(1, 6)]
=[f(3, 3)]+[f(1, 1)+f(2, 2)+f(1, 3)]+[f(1, 4)+f(2, 3)]+[f(1, 6)]

我们发现当篮子数目M= 2或M= 1时, 分类数目是显而易见的当M= 1时, f(1,N)= 1; 当M= 2时,f(2, N)= N/2(当N为奇数取整)(注意当篮子数目为2时要求两个篮子都放,不存在一个篮子不放的情况)。于是我们得到f(3, 1)= 1, f(2, 2)= 1, f(1, 3)= 1, f(1, 4)= 1, f(2, 3)= 1,f(1, 6)= 1。

我们现在还不知道f(3, 3)的值。

所以我们必须讨论最后一种情况:鸡蛋数目等于篮子数目。

如果按照之前的拆分方式,我们可以将f(3, 3)拆分为:

f(3, 3)= f(3, 0)+ f(2, 1)+ f(1, 2)= f(3, 0)+ f(1, 1)+ f(1, 2)

根据上述的方法我们很快就得到 f=f(2, 1)=f(1, 1)= 1, f(1, 2)= 1。但是我们不知道怎么求f(3, 0)。

为了搞清楚发f(3, 0)是什么,我们认真思考将3个鸡蛋放3个篮子的情况:3个篮子放都各放1个鸡蛋;1个篮子放1个鸡蛋,一个放2个,另一个不放;3个鸡蛋都放进1个鸡蛋,另外两个不放。我们发现1个篮子放1个鸡蛋,一个放2个,另一个不放的情况对应于f(2, 1)即f(1, 1),3个鸡蛋都放进1个鸡蛋,另外两个不放的情况对应于f(1, 2),剩下的3个篮子放都各放1个鸡蛋的情况只能对应于f(3, 0)。这样我们就知道f(3, 0)= 1。所以

f(3, 3)= f(3, 0)+ f(2, 1)+ f(1, 2)= f(3, 0)+ f(1, 1)+ f(1, 2)=1+1+1=3

类似我们试着去求f(4, 4),我们同样发现f(4, 0)= 1。所以根据不完全归纳,我们可以推出f(M, 0)= 1。

现在再回到之前的例子。

f(4,7)= f(4, 3)+f(3, 4)+f(2, 5)+f(1, 6)
= [f(3, 3)]+[f(3, 1)+f(2,2)+f(1, 3)]+[f(1, 4)+f(2, 3)]+[f(1, 6)]
=[f(3, 3)]+[f(1, 1)+f(2, 2)+f(1, 3)]+[f(1, 4)+f(2, 3)]+[f(1, 6)]
= 3+1+2+1+1+1+1+1=11

很明显这就是例子给出的结果。

如果我们将这种方法转化为代码时,我们要实现这种拆分,我们必须用到递归,注意写代码时将基本情况交代清楚,否则程序将出现错误。

我写的代码如下:

#include<stdio.h>
int main() { 
    int put(int basket, int egg);//引入f(M, N)函数 
    int number, i, egg[100], basket[100]; 
    scanf("%d", &number); 
    for (i= 0; i< number; i++) { 
        scanf("%d", &basket[i]); 
        scanf("%d", &egg[i]); 
    } 
    for (i= 0; i< number; i++) { 
        printf("%d\n", put(basket[i], egg[i])); 
    } 
}

int way= 0;

int put(int basket, int egg) { 
    int i; 
    int sum= 0; 
    if (basket<= egg) {
    //鸡蛋数目多于篮子数目的情况 
       if (basket== 2) way= egg/2;
       //f(2, N)情况 
       if (basket== 1) way= 1;
       //f(1, N)情况 
       if (egg== 0) way= 1;
       //f(M, 0)情况 
       else {
          if (egg>= 0) { 
             for (i= basket; i>= 1; i--) { 
                sum+= put(i, egg- i); 
             } 
             way= 0; 
             way+= sum; 
          }//进行拆分并对递归结果进行累加 
       } 
    } 
    else if (basket> egg) put(egg, egg);
     //鸡蛋数目少于篮子数目的情况 
    else {
    //篮子数目等于鸡蛋数目的情况 
       sum= 0; 
       for (i= basket; i>= 1; i--) { 
            sum+= put(i, egg-i); 
       } 
       way= sum; 
    } 
    return way;//输出最终结果 
}

另外附上标答的代码,用的就是我的方法,但标答的代码更简洁

#include<stdio.h>
int egg(int m, int n);

int main() { 
   int t; 
   // m for baskets, n for eggs 
   int m, n; 
   int result = 0; 
   scanf("%d", &t); 
   while (t--) {
      scanf("%d %d", &m, &n); 
      result = egg(m , n); 
      printf("%d\n", result); 
   } 
   return 0; 
}

int egg(int m, int n) { 
   if (m == 1 || n == 0) return 1; 
   if (n < 0) return 0; 
   return egg(m-1, n) + egg(m, n-m); 
}

Java源码-一筐鸡蛋问题的Java解法

朋友圈里看到一篇帖子: 一筐鸡蛋: 1个1个拿,正好拿完。 2个2个拿,还剩1个。 3个3个拿,正好拿完。 4个4个拿,还剩1个。 5个5个拿,还剩4个。 6个6个拿,还剩3个。 7个7个拿,正好拿...
  • hpdlzu80100
  • hpdlzu80100
  • 2016年10月17日 23:30
  • 2308

Google面试题-高楼扔鸡蛋问题

Google面试题-高楼扔鸡蛋问题 简单详尽的理解思路
  • lonelyrains
  • lonelyrains
  • 2015年06月09日 18:06
  • 6083

一道有趣的面试题——扔鸡蛋问题

现在很多大型IT企业在面试时都喜欢问一些智力相关的题目,虽然智力面试题在面试笔试中占的比例不大,但很多时候,面试环节中智力题往往会成为我们拿offer的最大拦路虎。因为有些面试官认为通过智力题可以考查...
  • Devil_2009
  • Devil_2009
  • 2014年09月17日 11:21
  • 3108

Google的一道面试题的推广(扔鸡蛋不破的层数,2个,3个,n个鸡蛋呢)

Google的面试题在论坛炒得很火,今年题目如下:“有一个100层高的大厦,你手中有两个相同的玻璃围棋子。从这个大厦的某一层扔下围棋子就会碎,用你手中的这两个玻璃围棋子,找出一个最优的策略,来得知那个...
  • chhuach2005
  • chhuach2005
  • 2014年09月08日 15:07
  • 1840

动态规划与数学方程法解决楼层扔鸡蛋问题

1.问题描述两个软硬程度一样的鸡蛋,它们有可能都在一楼就摔碎,也可能从一百层楼摔下来没事。有座100层的建筑,用这两个鸡蛋确定哪一层是鸡蛋可以安全落下的最高位置,可以摔碎两个鸡蛋,求给出一个最佳策略,...
  • K346K346
  • K346K346
  • 2016年09月23日 23:30
  • 1902

大楼扔鸡蛋问题(动态规划)

题目链接:poj 3783 题意分析: 小白书上的一道例题,4+2出了这道原题,我愣是以为是数学题,最后也没做出来。题意是这样的,给你N个鸡蛋(硬度一样),让你测鸡蛋的硬度,测量的方法就是从某栋M...
  • fuyukai
  • fuyukai
  • 2015年07月14日 19:49
  • 2421

线程 放鸡蛋咯

放鸡蛋 放鸡蛋 实体类package com.pojo; import java.io.Serializable; public class Egg implements Seriali...
  • qq_32000485
  • qq_32000485
  • 2016年12月21日 15:17
  • 53

经典谷歌面试题:高楼扔鸡蛋

经典谷歌面试题:高楼扔鸡蛋存在某T层高楼,在该高楼中存在这样的一层,在该层之下的所有楼层扔鸡蛋,鸡蛋摔到地上都不会碎,还可以继续扔;在该层及该层之上的所有楼层,扔下鸡蛋都会摔碎。 目前手里有两个鸡蛋...
  • siegecat
  • siegecat
  • 2016年09月12日 21:38
  • 373

100层楼扔两个鸡蛋的问题

两个软硬程度一样但未知的鸡蛋,它们有可能都在一楼就摔碎,也可能从一百层楼摔下来没事。 有座100层的建筑,要你用这两个鸡蛋确定哪一层是鸡蛋可以安全落下的最高位置。可以摔碎两个鸡蛋。  最少需要几次...
  • Kinger0
  • Kinger0
  • 2015年08月03日 21:28
  • 4970

蓝桥杯_格子放鸡蛋

答案:spy(da,r,c) /* N*N的格子 每行、每列、每个斜线 不能超过2个鸡蛋 */ public class A{ static int max = 0;//最多能下多...
  • qq_27782065
  • qq_27782065
  • 2016年05月26日 14:48
  • 226
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:放鸡蛋问题
举报原因:
原因补充:

(最多只允许输入30个字)