球盒问题之二:n分解成m正数和解题代码

球盒问题之二:n分解成m正数和解题代码

在上一篇博文 球盒问题之一:方案概览 中给出了S(n,m)的代码实现方案。
而对于前2种情况的解决方案并未给出代码与问题解决的思路。在这里,就将第一种与第二种情况下的解决问题的思路与代码分享。

思路:

第一种情况,n球同,m盒同,不空。记解为D(n,m)。
第二种情况,n球同,m盒同,可空,记解为H(n,m)。

那第一种情况与第二种情况有什么关系呢。先看第一种情况,因为所有盒子都不空,那所有盒子至少放一个球。那要是先将每个盒子都先放一个球呢,还剩下n-m个球要放到m个盒子中。而此时m个盒子中已经有一个球了,所以问题就退化成了将n-m个球放到m个盒子中,可以有空盒子这种情况下的解。

即 D(n,m)=H(n-m,m)。

而从上一篇博客我们已经知道了H(n,m)是D(n,1)加上D(n,2)。。。一直加到D(n,m)。

聪明如你,一定会想到,如果用数学来解决这个问题,那这就可以组成一个二元方程组。

而当用计算机解决这类方程式相关的问题时,就可以用动态规划相关的思路了。说白了就是递归调用直到将问题递归转化成最简单情况下的子集,然后求解。

解题代码如下:

class SplitNumToHeap
{
public:
    SplitNumToHeap():runTimes_(0){};
    virtual ~SplitNumToHeap(){};
    //盒不可空
    int splitNotEmpty(int ball,int box){
        if(ball == box || 1 == box)
            return 1;
        else if(ball<box)
            return 0;
        runTimes_++;
        return splitCanEmpty(ball-box,box);
    };

    //盒可空
    int splitCanEmpty(int ball,int box){
        if(1==box || 1==ball)
            return 1;
        return sumFunctionNotEmpty(ball,box);
    };

    //球数不变,盒数从1到最大值,计算盒不空所有放法之和。
    int sumFunctionNotEmpty(int ball,int boxMax){
        int result =0;
        for(int i=1;i<=boxMax;i++)
        {
            result+=splitNotEmpty(ball,i);
            runTimes_++;
        }
        return result;
    };

    //运行次数统计
    int getRunTimes(){return runTimes_;};
    void clear(){runTimes_=0;};

private:
    int runTimes_;

};

用盒不可空(n分解为m个数之和)做了几次测试,数据如下:

ball 100 put in box 99 can 1 runTimes 1
ball 100 put in box 50 can 204226 runTimes 543737
ball 100 put in box 25 can 7037286 runTimes 18973294
ball 100 put in box 10 can 2977866 runTimes 8313067
ball 100 put in box 2 can 50 runTimes 147
ball 10 put in box 4 can 9 runTimes 21
ball 10 put in box 5 can 7 runTimes 15
ball 8 put in box 5 can 3 runTimes 7
ball 8 put in box 3 can 5 runTimes 12
ball 8 put in box 4 can 5 runTimes 9
ball 8 put in box 6 can 2 runTimes 7
ball 9 put in box 6 can 3 runTimes 8
ball 11 put in box 6 can 7 runTimes 16
ball 5 put in box 6 can 0 runTimes 0
ball 5 put in box 3 can 2 runTimes 4
ball 15 put in box 3 can 19 runTimes 48
ball 15 put in box 8 can 15 runTimes 37

用几个参数核对了下,能对上。比如8分3个数和是和,10分2个数和是5等。

测试与打印代码基于Qt5.3,如下:

void MainWindow::on_BtnBallBox_clicked()
{
    SplitNumToHeap split;
    int ball=ui->lineEditBall->text().toInt();
    int box=ui->lineEditBox->text().toInt();
    int solutions=split.splitNotEmpty(ball,box);
    ui->lineEditSolutions->setText(QString::number(solutions));
    ui->lineEditRunTimes->setText(QString::number(split.getRunTimes()));
    std::cout<<"ball "<<ball<<" put in box "<<box<<" can "<<solutions<<" runTimes "<<split.getRunTimes()<<std::endl;
    split.clear();

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值