《正整数分解》题解
这道题是jlu程设2021的一道递归题目,题目如下:
问题描述:对于正整数n(n<=20),输出其和等于n的所有不增的正整数和式。
输入:从键盘随机输入一个正整数n。
输出:所有和为n的正整数和式,每个和式占一行。
样例1:
输入
4输出
4=3+1 4=2+2 4=2+1+1 4=1+1+1+1
样例2:
输入
5输出
5=4+1 5=3+2 5=3+1+1 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1
这道题显然是一个递归来解决的题目,首先我们显然能得到一个结论
对于任意的\(n\)与\(i\),若\(n\)有\(m\)种分解方式\(M_1,M_2,\cdots ,M_n\)(均为多项式),那么\(n+i\)必有\(m\)种分解方式\(i+M_1,i+M_2,\cdots ,i+M_n\).
因此,我们最开始的正整数分解的递归函数就出来了
void solve(int n){
if(i == 0){
print();//输出这个解
return ;
}
int i;
for(i = n; i > 0; i--){
//操作将i加入解中
solve(n-i);
}
return ;
}
然后我们发现要求是不增序列,所以上面的函数会出问题,我们需要对增的情况进行处理,显然, 我们多传一个上一次选择的数字是几就可以了。因此递归函数发生变化。
void solve(int n, int maxnum){
if(i == 0){
print();//输出这个解
return ;
}
int i;
for(i = n<maxnum ? n : maxnum; i > 0; i--){
//操作将i加入解中
solve(n-i, i);
}
return ;
}
这里有几个地方需要解释一下。
-
i = n<maxnum ? n : maxnum;这个玩意叫三目运算符,其作用等价于
if(n < maxnum) i = n; else i = maxnum; -
为什么要写这个三目运算符:因为存在\(maxnum>n\)的情况,在这个情况下,这个程序会陷入无限递归(\(solve\)函数的n传入了负的值,导致\(i--\)这一操作产生死循环和无限递归,同时产生了无数错误的解)
接下来就是存储解和输出了。
在这个情况下,显然不可能通过边操作边输出来成功输出正解,所以我们需要保存“进度”。
因此solve函数进一步补充:
void solve(int n, int maxnum){
if(n == 0){
print();//输出这个解
return ;
}
if(n < 0)
return ;//此操作为以防万一误入无限递归的处理:不输出直接返回上一层函数。
int i;
head++;//head为当前要写入的位置
for(i = n>maxnum?maxnum:n; i>0; i--){
ans[head] = i;//操作将i加入解中
solve(n-i, i<maxnum?i:maxnum);
}
head--;//这一层枚举完了,因此返回上一层继续枚举,要写入的位置也要返回上一个
return;
}
于是,输出解的函数也很容易就写出来了:
void print(){
printf("%d", ans[0]);
int i;
for(i = 1; i <= head; i++)
printf("+%d", ans[i]);
printf("\n");
}
此时我们发现一个问题,开头的等于我们没有,显然需要将题目中的n传至print函数中,因此solve及print中再加入一个参数pren,即得到如下程序。
#include<stdio.h>
int ans[50], head;
void print(int pren){
printf("%d=%d", pren, ans[0]);
int i;
for(i = 1; i <= head; i++)
printf("+%d", ans[i]);
printf("\n");
}
void solve(int pren, int n, int maxnum){
if(n == 0){
print(pren);
return ;
}
if(n < 0)
return ;
int i;
head++;
for(i = n>maxnum?maxnum:n; i>0; i--){
ans[head] = i;
solve(pren, n-i, i<maxnum?i:maxnum);
}
head--;
return;
}
int main(){
int n, i;
scanf("%d", &n);
for(i = n-1; i > 0; i--){
ans[0] = i;
head = 0;
solve(n, n-i, i);
}
}
浙公网安备 33010602011771号