《正整数分解》题解

这道题是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 ;
}

这里有几个地方需要解释一下。

  1. i = n<maxnum ? n : maxnum;
    

    这个玩意叫三目运算符,其作用等价于

    if(n < maxnum)
        i = n;
    else
        i = maxnum;
    
  2. 为什么要写这个三目运算符:因为存在\(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);
	}
}
posted @ 2021-12-23 23:09  WangZerong  阅读(324)  评论(0)    收藏  举报