整数按和拆分

  有这样的一个问题:把一个整数按和拆分,并列出所有的拆分
方式。比如对于3有如下的拆分方式:
3
= 1 + 2
= 1 + 1 + 1
= 2 + 1
  对于4则有
4
= 1 + 3
= 1 + 1 + 2
= 1 + 1 + 1 + 1
= 1 + 2 + 1
= 2 + 2
= 2 + 1 + 1
= 3 + 1
  显然,对于这样的一个问题,很容易想到用递归方式尝试一下。

1 #include <stdlib.h>
2 #include <stdio.h>
3
4 int kkk(int n, char *s)
5 {
6 char o[128];
7 int i;
8
9 if (1 == n)
10 {
11 return 0;
12 }
13
14 for (i = 1; i < n; i++)
15 {
16 printf("%s+%d+%d/n", s, i, n-i);
17
18 sprintf(o, "%s+%d", s, i);
19 kkk(n-i, o);
20 }
21
22 return 0;
23 }
24
25 int main(int argc, char *argv[])
26 {
27 /* TODO: Add your code here. */
28 kkk(5, "");
29
30 system("PAUSE");
31 return 0;
32 }

  这是一个种很直观的算法,处理较小的数据还好,但是对于较
大的数据,无论时间还是空间开销,都是不能接受的。
  不过,使用这个简单算法得出的结果,却为我分析拆分的规律
提供了依据。
注意到这些拆分形成有这样的规律:
 1、如果拆分串的最后数字n不等于1,则把n拆分为1和n-1放到
拆分串最后;
 2、如果拆分串的最后数字为1,设最后数字为拆分串的第k个(从
1开始算起)数字,则判断k-2是否小于1,若不小于1则把第k个数
字加到第k-2个数字上作为第k-2个数字,并且从拆分串中去掉第
k个数字;
 3、如果第2步中的k-2小于1则表示拆分结束。
  按照上面的思路,得到如下代码:
1 int aaa(int n)
2 {
3 int *p;
4 int i;
5
6 p = (int *)malloc((n + 1) * sizeof(int));
7 if (NULL == p)
8 {
9 printf("memory alloc failed./n");
10 return 1;
11 }
12
13 p[0] = 1;
14 p[1] = n;
15
16 while (1)
17 {
18 if (1 == p[p[0]])
19 {
20 if (p[0] < 3)
21 {
22 printf("%d = %d + %d/n", n,p[1],p[2]);
23 break;
24 }
25 else
26 {
27 p[p[0] - 2] += p[p[0]];
28 p[p[0]] = 0;
29 p[0]--;
30 }
31 }
32 else
33 {
34 p[p[0] + 1] = p[p[0]] - 1;
35 p[p[0]] = 1;
36 p[0]++;
37 }
38
39 printf("%d = %d", n, p[1]);
40 for (i = 2; i <= p[0]; i++)
41 {
42 printf(" + %d", p[i]);
43 }
44 printf("/n");
45 }
46
47 free(p);
48 return 0;
49 }
  去递归后的代码,在时间和空间上的要求都比递归版本的少得
多,纯粹运算的话,可以处理较大的数值了。但数值较大时,完成
输出将是一个问题:-)。
  如果不考虑拆分的顺序差异,如何去除上面算法的重复输出?
对我而言,现在还是个问题。

3.141592653589793238462643383
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值