7-37 整数分解为若干项之和

将一个正整数N分解成几个正整数相加,可以有多种分解方法,例如7=6+1,7=5+2,7=5+1+1,…。编程求出正整数N的所有整数分解式子。

输入格式

每个输入包含一个测试用例,即正整数N (0<N≤30)。

输出格式

按照递增顺序输出N的所有整数分解式子。递增顺序是指:对于两个分解序列N1={n1,n2,}N2={m1,m2,},若存在i使得n1=m1,,ni=mi,但是ni+1<mi+1,则N1序列必定在N2序列之前输出。每个式子由小到大相加,式子间用分号隔开,且每输出4个式子后换行。

输入样例

7

输出样例

7=1+1+1+1+1+1+1;7=1+1+1+1+1+2;7=1+1+1+1+3;7=1+1+1+2+2
7=1+1+1+4;7=1+1+2+3;7=1+1+5;7=1+2+2+2
7=1+2+4;7=1+3+3;7=1+6;7=2+2+3
7=2+5;7=3+4;7=7

分析与答案

这题我只想到了应该是递归的思想,但最后也没想出来,抄答案的(但分析是我的)。

下面的程序不仅有递归的元素,也有栈的元素在。程序建立了一个足够大的栈和栈顶指针,并建立了变量记录输出的次数和栈中元素的和(这些都作为全局变量存在)。在递归中,每一层对应的都是一个栈元素的插入循环,终点都是输入的正整数,而起点与栈中元素的位置和大小有关,每一层的起点都是前一层(也就是上一个栈元素)的当前数值,以此类推,这样可以保证输出可以满足题目要求的递增顺序。整个递归的思路如下:

  1. 如果当前记录的求和值与输入数值相等,则按照题目要求输出当前的求和式,再返回到上一层递归继续执行;
  2. 如果当前记录的求和值大于输入数值,则直接返回;
  3. 如果不是上述情况,那就将当前栈顶指针向前移动并放入数值(也就是执行入栈操作,具体是哪个值见上述分析),sum也加上对应数值,进入下一层递归;
  4. 无论下一层递归的结果是直接返回还是输出了,此时栈顶的元素都要取出,sum也要重新减去对应数值。

到了栈中只有输入的数值n时,对下一层的所有操作都会导致sum值大于n从而直接返回,因此在输出n=n后整个递归过程就自动结束。

在输出时需要注意,每输出4次求和式就要换一次行,输出到最后n=n时也是换行,其他时候则输出分隔符;

#include<stdio.h>

int N;

int s[31]; // 存放划分结果,这里用了比较简单地容器,数组,比我想象的要简单 
int top = -1; // 数组指针 
int count = 0; // 统计输出的次数 
int sum = 0; // 拆分项累加和 

void division (int i);

int main (){
    scanf ("%d", &N);
    division (1);
    return 0; 
}

void division (int i) {//拆分 
    if (sum == N) {
        count ++;
        printf("%d=", N);
        int k;
        for (k=0; k<top; k++) {
            printf("%d+", s[k]);
        }
        if (count%4 == 0 || s[top] == N) {
            printf("%d\n", s[top]);
        } else {
            printf("%d;", s[top]);
        }
        return;
      } // 输出部分 
    if (sum > N) {
        return;
    }
    for (int j=i; j<=N; j++) { 
        s[++top] = j;
        sum += j; 
        division (j);
        sum -= j;
        top --;
    } // 算法主体 
}

7-37 测试点