论坛首页 综合技术论坛

拆解数字

浏览 18570 次
锁定老帖子 主题:拆解数字
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2011-03-18  
Excalibur 写道
ggzwtj 写道
悲催啊,要输出所有结果,再怎么弄都是浮云,快不起来了。200的分解方法应该是3972999029388种吧。。。。

我算到40就eclipse就挂了……

我的57还能抗住,58就OutOfMemoryError了。谁能帮我把我的递归修成循环啊 ,探索中...
0 请登录后投票
   发表时间:2011-03-18  
dongya1987 写道
Excalibur 写道
ggzwtj 写道
悲催啊,要输出所有结果,再怎么弄都是浮云,快不起来了。200的分解方法应该是3972999029388种吧。。。。

我算到40就eclipse就挂了……

我的57还能抗住,58就OutOfMemoryError了。谁能帮我把我的递归修成循环啊 ,探索中...

你的速度如何?
0 请登录后投票
   发表时间:2011-03-18  
Excalibur 写道
ggzwtj 写道
悲催啊,要输出所有结果,再怎么弄都是浮云,快不起来了。200的分解方法应该是3972999029388种吧。。。。

我算到40就eclipse就挂了……

不至于吧,40的时候只有37338种分解。
0 请登录后投票
   发表时间:2011-03-18  
好吧,我觉得如果非得输出所有的情况反而使得问题变得简单,因为我们没有必要考虑优化了。下面是代码:
import java.math.BigInteger;
import java.util.Scanner;

/**
* @author tianchi.gzt
*
* 求数字n的拆分的方法的总数(不考虑顺序)
*/
public class test{
static int[] a = new int[100];
static int result = 0;
public static void show(int n, int m, int big){
if(n == 0){
result++;
System.out.print("= " +a[0]);
for(int i = 1; i < m; i++){
System.out.print(" + " + a[i]);
}
System.out.println();
}
int i;
if(n > big){
i = big;
}else{
i = n;
}
for(; i > 0; i--){
a[m] = i;
show(n-i, m+1, i);
}
}
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while(true){
result = 0;
int tmp = scanner.nextInt();
System.out.println(tmp);
show(tmp, 0, tmp);
System.out.println(result);
}
}
}
这里说明一下啊,如果是非得输出的话,肯定是非常慢的,有那么多要输出的东西。如果把输出的部分去掉的话,速度还是很快的。
0 请登录后投票
   发表时间:2011-03-18  
import java.math.BigInteger;
import java.util.Scanner;

/**
* @author tianchi.gzt
*
* 求数字n的拆分的方法的总数(不考虑顺序)
*/
public class test{
static int[] a = new int[100];
static int result = 0;
public static void show(int n, int m, int big){
if(n == 0){
result++;
System.out.print("= " +a[0]);
for(int i = 1; i < m; i++){
System.out.print(" + " + a[i]);
}
System.out.println();
}
int i;
if(n > big){
i = big;
}else{
i = n;
}
for(; i > 0; i--){
a[m] = i;
show(n-i, m+1, i);
}
}
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while(true){
result = 0;
int tmp = scanner.nextInt();
System.out.println(tmp);
show(tmp, 0, tmp);
System.out.println(result);
}
}
}
0 请登录后投票
   发表时间:2011-03-18  
输出的话在50以内不是非常慢,不输出的话在90以内不是非常慢
0 请登录后投票
   发表时间:2011-03-20   最后修改:2011-03-24
#include <stdio.h>
#include <assert.h>

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<s ; i++ )
		{
			printf(" + %d", steps[i]);
		}
		printf(" + %d\n", x);
	}
#endif
	n += 1;
	assert( n > 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;
}


0 请登录后投票
   发表时间:2011-03-21  
ccjsjymg 写道

LONG f(int x, int y
#ifdef PRINT_RESULT
	, int print
#endif
)
...
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;
}




学习了,原来宏还可以这么用
0 请登录后投票
   发表时间:2011-03-22  
ggzwtj 写道
ggzwtj 写道
这个可以用动态规划来做:
状态:dp[x][y]表示将x拆分成的最大值为y的方法总数。
过程:dp[x][y] = dp[x-y][1] + dp[x-y][2] + … +dp[x-y][y];
结果:result = dp[n][1] + dp[n][2] + dp[n][3] + … + dp[n][n];

ps:过程中要小心数组越界(要是有代码需求我帮你写哈

import java.util.Scanner;

/**
* @author tianchi.gzt
*
* 求数字n的拆分的方法的总数(不考虑顺序)
*/
public class test {
int[][] dp;
int n;
public test(){
}
public void setN(int n){
this.n = n;
dp = new int[n+1][n+1];
dp[1][1] = dp[0][0] =1;

for(int i = 2; i <= n; i++){
for(int j = 1; j <= i; j++){
for(int k = 0; k <= j; k++){
dp[i][j] += dp[i-j][k];
}
}
}
}
public int solve(){
int result = 0;
for(int i = 1; i <= n; i++){
result += dp[n][i];
}
return result;
}
public void show(){
for(int i = n; i >= 0; --i){
for(int j = 0; j <=n; j++){
System.out.print(dp[i][j] + " ");
}
System.out.println();
}
}
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
test a = new test();
while(true){
a.setN(scanner.nextInt());
a.show();
System.out.println(a.solve());
}
}
}

现在补充代码,测试过了,可以算出来,可以看出具体的分法的大概。:) 休息吧。。。


顶,最喜欢动态规划了,虽然不太熟
0 请登录后投票
   发表时间:2011-03-22  
buptwhisper 写道
不考虑顺序问题,也可以改用组合方式,如下:
对于n = 1 + 1 + 1 + 1 + ... + 1这列组合加数,其中的 + 取任意个(大于等于1个),即从n-1个加号中任意取出m个 1<=m<=n-1,这就对应着一个拆数
所以拆数就是2^(n-1) - 1种。

这个会重复很多吧````
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics