题目描述: 整数拆分
整数5可以被拆分为6种不同的式子,如下:
4 + 1
3 + 2
3 + 1 + 1
2 + 2 + 1
2 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1
请问100可以被拆分为多少种不同的式子呢?
解答
用递归和动态规划的思想,用非递增的方式选择用于整数N拆分的每一个数,对每个数都有选择和不选择两种可能。
开始的时候和sum = 0(sum是以前选择的所有数的和,每做出一种选择,都对N-sum这个新数进行拆分), 第一个可供选择的数是1,遍历1~N的每个数,都是一种选择。
如果第一个选择的数是1,然后递归的拆分整数N-1,第一个可供选择的数还是1;
如果第一个选择的数是2,然后递归的拆分整数N-2,第一个可供选择的数是2(非递减的思想保证用于拆分的序列不重复);
……
#include <iostream>
using namespace std;
int n, cnt;
void solve(int sum, int pre)
{
if(sum==n)
{
cnt++; //拆分成功,计数器加1
return ;
}
for(int i = pre; i<=n-sum; i++)
{
solve(sum+i, i);
}
}
int main()
{
while(cin>>n){
cnt = 0;
solve(0, 1); //最初的和是0,可供选择的数是1(用于拆分的每个数都至少是1)
cout<<cnt-1<<endl; //最终结果减1是为了除去 N(+0)=N 这种拆分方法
}
return 0;
}
刚刚看了一下这位大神的博客,学到了如何把各种组合的结果输出,代码和注释如下。
#include <iostream>
using namespace std;
int n, cnt;
int data[100]; //用于存储所有选择的数
int datasize; //用于指示当前data数组的大小
void solve(int sum, int pre)
{
if(sum==n) //当拆分成功的时候将data数组中的数输出
{
cnt++;
if(datasize>1){ //大于1是为了除去N这种拆分结果
cout<<data[0];
for(int i = 1; i<datasize; i++)
cout<<"+"<<data[i];
cout<<endl;
}
return ;
}
for(int i = pre; i<=n-sum; i++)
{
data[datasize++] = i; //选择i,将i存入data数组
solve(sum+i, i);
datasize --; //不选择i,将data数组的大小减一,相当于删除i
}
}
int main()
{
cout<<"Input: ";
while(cin>>n){
cnt = 0;
solve(0, 1);
cout<<"Output: "<<cnt-1<<endl;
cout<<"Input: ";
}
return 0;
}
最后的运行结果:
增加一点东西,如果要求拆分后的各项不相等,可以考虑按照严格递增的顺序选择新加入的数。
#include <iostream>
using namespace std;
int n, cnt;
int data[100]; //用于存储所有选择的数
int datasize; //用于指示当前data数组的大小
void solve(int sum, int pre)
{
if(sum==n) //当拆分成功的时候将data数组中的数输出
{
cnt++;
if(datasize>1){ //大于1是为了除去N这种拆分结果
cout<<data[0];
for(int i = 1; i<datasize; i++)
cout<<"+"<<data[i];
cout<<endl;
}
return ;
}
for(int i = pre+1; i<=n-sum; i++) //如果要求各数不相等,则按照严格递增的顺序选择(pre+1)
{
data[datasize++] = i; //选择i,将i存入data数组
solve(sum+i, i);
datasize --; //不选择i,将data数组的大小减一,相当于删除i
}
}
int main()
{
cout<<"Input: ";
while(cin>>n){
cnt = 0;
solve(0, 0);
cout<<"Output: "<<cnt-1<<endl;
cout<<"Input: ";
}
return 0;
}
运行结果如下: