觉得这个童鞋的分析很劲道:
http://www.iteye.com/topic/963980?page=2
假设拆解10,那么我们有一下几种分法
10 =9 + 1
=8 + 2 =8 + 1 + 1
=7 + 3 =7 + 2 + 1 =7 + 1 + 1 + 1
=6 + 4 =...(到这里的时候,我们看一下前面的3行,第1行是9+1,第2行是8+(2的两种拆分),第3行是7+(3的3种拆分拆分),到本行就是6+(4的各种拆分))
=5 + 5的各种拆分
=4 + ...(到这里我们不能用6的各种拆分,因为这样会与前面的数据有所重合,要保证这里每行的数据与其他行的数据不重合,我采用的方法是第一行每种拆分的最大值都是9,第二行的拆分的最大值都是8,到本行拆分的最大值应该是。所以,应该是4+小于等于4的书对6的拆分)
=3 + 小于等于3的数对7的各种拆分
=2 + 小于等于2的数对8的各种拆分
=1 + 小于等于1的数对9的各种拆分
如果,我们把小于等于x的数对于y的拆分表示成f(x,y),则上面的式子可以表示为:
10 =9 + f(1,1)
=8 + f(2,2)
=7 + f(3,3)
=6 + f(4,4)
=5 + f(5,5)
=4 + f(4,6)
=3 + f(3,7)
=2 + f(2,8)
=1 + f(1,9)
看上面的式子能得出一个规律,1-5行实际上是1的拆分、2的拆分、3的拆分、4的拆分、5的拆分;
4-9行是f(n,10-n), n<5
这就需要研究f(x,y)的递归规律,
举例: f(3,5) = 3 + f(3, 2)
= 2 + f(2, 3)
= 1 + f(1, 4)
不难得出其中的循环规律。代码为:
import java.util.ArrayList; import java.util.List; public class TestHello { public static void main(String[] args) { final int NUM = 10; Listlist = f(NUM, NUM); int total = list.size(); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("数字"+NUM+"共有" + total + "种拆法"); } /** * 小于等于x的数对y的拆分 * * @return List的每一个元素为一种拆分情况 */ static List f(int x, int y) { if (x < 1 || y < 1) return null; if (x > y) { return f(y, y); // 小于等于3的数对2的拆分,跟小于等于2的数对2的拆分实际上是一样的 } List result = new ArrayList (); if (x == 1) { StringBuilder sb = new StringBuilder("1"); for (int i = 1; i < y; i++) { sb.append("+1"); } result.add(sb.toString()); return result; }else if (x == 2 && y == 2) { result.add("1+1"); result.add("2"); return result; }else{ if (x == y) { result.add("" + x); } for (int i = x; i > 0; i--) { List l = f(i, y - i); if(l==null){ continue; } for (int j = 0; j < l.size(); j++) { String s = i + "+" + l.get(j); result.add(s); } } } return result; } }
.
还在一起探索:
Excalibur 写道
ggzwtj 写道
悲催啊,要输出所有结果,再怎么弄都是浮云,快不起来了。200的分解方法应该是3972999029388种吧。。。。
我算到40就eclipse就挂了……
我的57还能抗住,58就OutOfMemoryError了。谁能帮我把我的递归修成循环啊 ,探索中...
http://www.iteye.com/topic/963980?page=4
#include#include typedef long long LONG; #define N 1000 LONG sr[N][N]; #ifdef _DEBUG #define PRINT_RESULT #endif #ifdef PRINT_RESULT int steps[N]; #endif LONG f(int x, int y #ifdef PRINT_RESULT , int print #endif ) { #ifdef PRINT_RESULT static int s = 0; int i =0; assert(s < N); #endif if(!print) if(sr[x][y]) return sr[x][y]; LONG n = 0; int original_y = y; assert(x >= y && y > 0); while(x - y >= y) { #ifdef PRINT_RESULT if(print) steps[s++] = y; #endif n += f(x-y, y #ifdef PRINT_RESULT , print #endif ); assert( n > 0); //avoid integer overflow #ifdef PRINT_RESULT --s; #endif ++ y; } #ifdef PRINT_RESULT if(print) { for (i=0; i 0); if(!print) return sr[x][original_y] = n; else return n; } void init() { memset(sr, 0, sizeof(sr)); } int main(int argc, char ** argv) { int input; LONG n = 0; int print = 0; if(argc > 1 && 0 == strcmp(argv[1], "print")) print = 1; assert( sizeof(LONG) == 8); while(scanf("%d", &input)!=EOF) { init(); n = f(input, 1 #ifdef PRINT_RESULT ,print #endif ); printf("%lld\n", n ); } return 0; }
.