用动态规划解小朋友分糖问题

     为了解决谷歌一道题,想了个非主流的招数。原题是:“10块都相同的糖分给3个小朋友,每个小朋友至少分到一块糖,有几种分配方式?”,细细一想其实就是每个小朋友一块糖的前提下,再分7块糖,就是把7块糖分给3个小朋友的种类数,也就是这个二维数组中DP[2][6]的取值。

  这题完全可以用排列组合来做,穷举各种可能性后乘以组合数,答案是36。

  用动态规划的思路比较奇特。。总感觉发现了什么奥秘,却又阐释不清楚,大概说一说吧:

  拿3块糖分给3个小朋友这个问题作为分析例子:

  1、选择一个小朋友不给他糖(怪蜀黍都这么干!),然后把剩下的3块糖分给其他2个小朋友(一共有4种方式)

  2、回顾一下,之前算出的值,把2块糖分给3个小朋友有6种方式,在这六种每种的基础上再加一块糖分给三个小朋友,得出这样的分配方式不能够和上边3块糖分给2个小朋友的分配方式重复,最终可以生成6种不重复的分配方式,最后一共有6+4种分配方式。

  上个图:

  

    可以看到,左边是3个人分2块糖的分配方式,右边上半部分是2个人分3块糖的分配方式。左边的列通过一次状态转化(再加一块糖给三个小朋友)即可达到右边的列的状态路径已经连上了线。比如{0,0,2}可以通过加一块糖变成{0,0,3}{0,1,2}{1,0,2},但其中第一个小朋友没有分到糖的情况已经在右边上半部分出现过了,于是只能把糖给那个没有糖的小朋友才能产生出新的状态,即{1,0,2},同理{0,2,0}和{0,1,1}都只能对应一种状态。

    最后三种状态同理也只能把新加的一块糖给第一个小朋友,于是又对应三种状态(不通的路径用红色标出,绿色标出的是可行状态转化路径)。

#include <stdio.h>

static const int S=10; //S块糖
static const int C=3;   //C个小朋友

int main()
{
    int DP[C][S]={0};

    //初始化
    for (int i=0;i<S;i++)
    {
        DP[0][i]=1; //分给一个小朋友不管分多少糖都只有一种分法
    }
    for (int i=0;i<C;i++)
    {
        DP[i][0]=i+1; //把一块糖分给i个小朋友有i种方法
    }

    for(int i=1;i<C;i++)
    {
        for(int j=1;j<S;j++)
        {
            DP[i][j]=DP[i-1][j]+DP[i][j-1]; //状态转移公式,比如三块糖分给三个小朋友就等于3块糖分给2个小朋友加上2块糖分给3个小朋友
        }
    }

    //输出

    for(int i=0;i<C;i++)
    {
        for(int j=0;j<S;j++)
        {
            printf("%d, ",DP[i][j]);
        }
        printf("\n");
    }

    system("pause");
}

转载于:https://www.cnblogs.com/darknightsnow/archive/2012/10/17/2728432.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值