球盒问题之三: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