球盒问题之三:n分解成m个正数和所有组合

球盒问题之三:n分解成m个正数和所有组合

问题

将正整数n分解成m个正整数之和,给出所有组合。此问题等同于等同于n个球放到m个盒子中,盒子不能为空,球与盒子都完全相同。

算法

这个问题并不难,只要把去重的问题解决,基本都能给出正确的算法。

此处用有序数列的方式给出一种算法。不保证算法很高效啊。:)。如有更好的算法,请推荐下啊。

用有序数列来解决去重的问题,即得出的结果用一个二维数组保存,一行为一个结果,但保证每行中的数都是按从小到大或者从大到小的顺序排列,且各行不相同。如此,写一个从1开始遍历到n/m的循环,然后每层均进行递归。

部分代码

代码如下:

std::vector<std::vector<int> > Permute::sumNToDst(int dst, int n)
{
    std::vector<std::vector<int> > r;
    findUpSeq(1,n,dst,r);
    std::cout<<r.size()<<" solutions "<<std::endl;
    for(int i=0;i<r.size();i++){
        for(int j=0;j<r.at(i).size();j++){
            std::cout<<r.at(i).at(j)<<" ";
        }
        std::cout<<std::endl;
    }
}


/**
 * @brief Permute::findUpSeq
 * @param low       盒子中最少放置的球数
 * @param num       盒子数
 * @param sum       球总数
 * @param result    返回二维数组分配结果
 * @return          是否分配成功
 */
int Permute::findUpSeq(int low, int num,int sum, vector<vector<int> > &result)
{
    result.clear();
    if(num<1||sum<0)
        return 0;
    //只有一个盒子
    if(num==1){
        if(sum>=low){
            std::vector<int> v;
            v.push_back(sum);
            result.push_back(v);
            return 1;
        }
        return 0;
    }else if(num<1){
        return 0;
    }
    //球数少于每个盒子应放总数之和
    if(sum<num*low)
        return 0;
    else if(sum == num*low){
        std::vector<int> t;
        t.assign(num,low);
        result.push_back(t);
        return low;
    }

    std::vector<std::vector<int> > s;
    //依次给1号盒子放1-n/m个球,将剩下的球放到剩下的盒子中且保证后续盒子球数不低于前一盒子
    for(int i=low;((i*num)<sum+1);i++){
        s.clear();
        //如果后续盒子放置成功,将其放置方案中加入1号盒子中所放球数做为一个方案
        if(findUpSeq(i,num-1,sum-i,s)){
            for(int j=0;j<s.size();j++){
                s.at(j).push_back(i);
                result.push_back(s.at(j));
                for(int k=0;k<s.at(j).size();k++){
                    std::cout<<" "<<s.at(j).at(k);
                }
            }
            std::cout<<std::endl;

        }
    }
    return 1;
}

测试

测试代码:

Permute per;

per.sumNToDst(25,5);

测试结果

192 solutions 
21 1 1 1 1 
20 2 1 1 1 
19 3 1 1 1 
18 4 1 1 1 
17 5 1 1 1 
16 6 1 1 1 
15 7 1 1 1 
14 8 1 1 1 
13 9 1 1 1 
12 10 1 1 1 
11 11 1 1 1 
19 2 2 1 1 
18 3 2 1 1 
17 4 2 1 1 
16 5 2 1 1 
15 6 2 1 1 
14 7 2 1 1 
13 8 2 1 1 
12 9 2 1 1 
11 10 2 1 1 
17 3 3 1 1 
16 4 3 1 1 
15 5 3 1 1 
14 6 3 1 1 
13 7 3 1 1 
12 8 3 1 1 
11 9 3 1 1 
10 10 3 1 1 
15 4 4 1 1 
14 5 4 1 1 
13 6 4 1 1 
12 7 4 1 1 
11 8 4 1 1 
10 9 4 1 1 
13 5 5 1 1 
12 6 5 1 1 
11 7 5 1 1 
10 8 5 1 1 
9 9 5 1 1 
11 6 6 1 1 
10 7 6 1 1 
9 8 6 1 1 
9 7 7 1 1 
8 8 7 1 1 
18 2 2 2 1 
17 3 2 2 1 
16 4 2 2 1 
15 5 2 2 1 
14 6 2 2 1 
13 7 2 2 1 
12 8 2 2 1 
11 9 2 2 1 
10 10 2 2 1 
16 3 3 2 1 
15 4 3 2 1 
14 5 3 2 1 
13 6 3 2 1 
12 7 3 2 1 
11 8 3 2 1 
10 9 3 2 1 
14 4 4 2 1 
13 5 4 2 1 
12 6 4 2 1 
11 7 4 2 1 
10 8 4 2 1 
9 9 4 2 1 
12 5 5 2 1 
11 6 5 2 1 
10 7 5 2 1 
9 8 5 2 1 
10 6 6 2 1 
9 7 6 2 1 
8 8 6 2 1 
8 7 7 2 1 
15 3 3 3 1 
14 4 3 3 1 
13 5 3 3 1 
12 6 3 3 1 
11 7 3 3 1 
10 8 3 3 1 
9 9 3 3 1 
13 4 4 3 1 
12 5 4 3 1 
11 6 4 3 1 
10 7 4 3 1 
9 8 4 3 1 
11 5 5 3 1 
10 6 5 3 1 
9 7 5 3 1 
8 8 5 3 1 
9 6 6 3 1 
8 7 6 3 1 
7 7 7 3 1 
12 4 4 4 1 
11 5 4 4 1 
10 6 4 4 1 
9 7 4 4 1 
8 8 4 4 1 
10 5 5 4 1 
9 6 5 4 1 
8 7 5 4 1 
8 6 6 4 1 
7 7 6 4 1 
9 5 5 5 1 
8 6 5 5 1 
7 7 5 5 1 
7 6 6 5 1 
6 6 6 6 1 
17 2 2 2 2 
16 3 2 2 2 
15 4 2 2 2 
14 5 2 2 2 
13 6 2 2 2 
12 7 2 2 2 
11 8 2 2 2 
10 9 2 2 2 
15 3 3 2 2 
14 4 3 2 2 
13 5 3 2 2 
12 6 3 2 2 
11 7 3 2 2 
10 8 3 2 2 
9 9 3 2 2 
13 4 4 2 2 
12 5 4 2 2 
11 6 4 2 2 
10 7 4 2 2 
9 8 4 2 2 
11 5 5 2 2 
10 6 5 2 2 
9 7 5 2 2 
8 8 5 2 2 
9 6 6 2 2 
8 7 6 2 2 
7 7 7 2 2 
14 3 3 3 2 
13 4 3 3 2 
12 5 3 3 2 
11 6 3 3 2 
10 7 3 3 2 
9 8 3 3 2 
12 4 4 3 2 
11 5 4 3 2 
10 6 4 3 2 
9 7 4 3 2 
8 8 4 3 2 
10 5 5 3 2 
9 6 5 3 2 
8 7 5 3 2 
8 6 6 3 2 
7 7 6 3 2 
11 4 4 4 2 
10 5 4 4 2 
9 6 4 4 2 
8 7 4 4 2 
9 5 5 4 2 
8 6 5 4 2 
7 7 5 4 2 
7 6 6 4 2 
8 5 5 5 2 
7 6 5 5 2 
6 6 6 5 2 
13 3 3 3 3 
12 4 3 3 3 
11 5 3 3 3 
10 6 3 3 3 
9 7 3 3 3 
8 8 3 3 3 
11 4 4 3 3 
10 5 4 3 3 
9 6 4 3 3 
8 7 4 3 3 
9 5 5 3 3 
8 6 5 3 3 
7 7 5 3 3 
7 6 6 3 3 
10 4 4 4 3 
9 5 4 4 3 
8 6 4 4 3 
7 7 4 4 3 
8 5 5 4 3 
7 6 5 4 3 
6 6 6 4 3 
7 5 5 5 3 
6 6 5 5 3 
9 4 4 4 4 
8 5 4 4 4 
7 6 4 4 4 
7 5 5 4 4 
6 6 5 4 4 
6 5 5 5 4 
5 5 5 5 5 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值