论坛首页 综合技术论坛

拆解数字

浏览 18432 次
锁定老帖子 主题:拆解数字
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2011-03-28  
数学都不错啊 
0 请登录后投票
   发表时间:2011-04-02   最后修改:2011-04-02

C++版的:

/*
输入一个整数,如:整数7它的和为 N1+N2+...+Nk=7,且 N1>=N2>=..>=Nk(k>=1),
将其拆分,并打印出各种拆分.对于7有: 6+1=7..5+2=7....1+1+1+1+1+1+1=7共有14种拆分方法。
分解过程:
输入3:
				      (对5分解)  5=4+1             5=3+2   
				(用递归对4分解)    4=3+1     4=2+2
                			(用递归对3分解)      3=2+1
				(用递归对2分解)	 2=1+1
*/

#include<iostream>
#include<list>

using namespace std;

int count=0;//记录总的分解方法
int temp=0;

list<int> ilist;  //保存分解过程中产生的每种分解方法

void divide(int num, int flag);
void print(list<int> ilist, int num)	//打印每种分解方法
{
	list<int>::iterator ibegin, iend;
	ibegin=ilist.begin();
	iend=ilist.end();
	if(ibegin==iend)
	{
		cout<<"The list is empty!"<<endl;
		exit(EXIT_FAILURE);
	}
	cout<<num<<" = "<<*ibegin;
	ibegin++;
	while(ibegin!=iend)
	{
		cout<<"+"<<*ibegin;
		ibegin++;
	}
	cout<<endl;
}

int main()
{
	cout<<"Please inpu the num:"<<endl;
	int num;
	while(cin>>num , num<=0)
	{
		cout<<"请输入大于0的正整数!"<<endl;
	}
	temp=num;
	divide(num,1);//第二个参数可以改变(>0)
	cout<<"共有: "<<count<<" 种分法!"<<endl;
	return 0;
}

void divide(int num, int flag)
{

	if(num==flag)	//当num==flag时到了最底层的分解
	{
		if(!ilist.empty())
		{
			ilist.pop_front();
		}
		ilist.push_front(flag);
		
		print(ilist,temp);
		ilist.pop_front();  //当递归回退一层时删除list中的第一个元素
		return;
	}
	if(!ilist.empty())
	{
		print(ilist,temp);//每次进入divide一次就产生了一种分法,将其打印输出
	}
	for(int i=flag; i<=num/2; i++)
	{
		count++;

		if(!ilist.empty())		
		{
			ilist.pop_front();	//对于ilist.front()产生了一种分解方法,
		}
		ilist.push_front(i);	//将ilist.front()取出并将两分解元素push到ilist头部
		ilist.push_front(num-i);

		divide(num-i,i);//递归
	}
	if(!ilist.empty())
	{
		ilist.pop_front();//当递归回退一层时删除list中的第一个元素
	}	
}

  

 

0 请登录后投票
   发表时间:2011-04-08  
来个清爽的,随手写的,不保证一定正确,简单测了一下,应该没有问题。

public class Test {

	public static LinkedList<Integer> stack = new LinkedList<Integer>();

	public static int num = 5;

	public static void main(String[] args) {
		stack.add(1);
		decompose(num);
	}

	// 为了避免重复,所以拆解以后后面的数据>=前面的数字:4=1+3或2+2,5=1+4或2+3...
	public static void decompose(int i) {
		for (int j = stack.getLast(); j <= i / 2; j++) {
			stack.add(j);
			// 首先拆解的第二个数是满足条件的,所以先打印出来,再递归拆解第二个数
			stack.add(i - j);
			print();
			stack.removeLast();
			decompose(i - j);
			stack.removeLast();
		}
	}

	public static void print() {
		System.out.print(num + "=");
		for (int i = 1; i < stack.size(); i++) {
			System.out.print(i < stack.size() - 1 ? stack.get(i) + "+" : stack.get(i));
		}
		System.out.println();
	}

}


5=1+4
5=1+1+3
5=1+1+1+2
5=1+1+1+1+1
5=1+2+2
5=2+3
0 请登录后投票
   发表时间:2011-04-18  
public class SplitNum {
	public static void main(String[] args) {
		System.out.println("一共有" + splitNumber(20) + "种分法");
	}

	public static int splitNumber(int a) {
		return splitNumberWithMax(a, a, 0, a+" = ");
	}

	private static int splitNumberWithMax(int max, int tag, int c, String s) {
		if (tag == 1 || tag == 0) {
			System.out.println(tag == 1 ? (s + tag ) : s.substring(0,s.length()-2));
			c++;
		} else {
			for (int i = (max >= tag ? tag : max); i > 0; i--) {
				c = splitNumberWithMax(i, tag - i, c, s + i + " + ");
			}
		}
		return c;
	}
}

10 = 10
10 = 9 + 1
10 = 8 + 2
10 = 8 + 1 + 1
10 = 7 + 3
10 = 7 + 2 + 1
10 = 7 + 1 + 1 + 1
10 = 6 + 4
10 = 6 + 3 + 1
10 = 6 + 2 + 2
10 = 6 + 2 + 1 + 1
10 = 6 + 1 + 1 + 1 + 1
10 = 5 + 5
10 = 5 + 4 + 1
10 = 5 + 3 + 2
10 = 5 + 3 + 1 + 1
10 = 5 + 2 + 2 + 1
10 = 5 + 2 + 1 + 1 + 1
10 = 5 + 1 + 1 + 1 + 1 + 1
10 = 4 + 4 + 2
10 = 4 + 4 + 1 + 1
10 = 4 + 3 + 3
10 = 4 + 3 + 2 + 1
10 = 4 + 3 + 1 + 1 + 1
10 = 4 + 2 + 2 + 2
10 = 4 + 2 + 2 + 1 + 1
10 = 4 + 2 + 1 + 1 + 1 + 1
10 = 4 + 1 + 1 + 1 + 1 + 1 + 1
10 = 3 + 3 + 3 + 1
10 = 3 + 3 + 2 + 2
10 = 3 + 3 + 2 + 1 + 1
10 = 3 + 3 + 1 + 1 + 1 + 1
10 = 3 + 2 + 2 + 2 + 1
10 = 3 + 2 + 2 + 1 + 1 + 1
10 = 3 + 2 + 1 + 1 + 1 + 1 + 1
10 = 3 + 1 + 1 + 1 + 1 + 1 + 1 + 1
10 = 2 + 2 + 2 + 2 + 2
10 = 2 + 2 + 2 + 2 + 1 + 1
10 = 2 + 2 + 2 + 1 + 1 + 1 + 1
10 = 2 + 2 + 1 + 1 + 1 + 1 + 1 + 1
10 = 2 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
10 = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
一共有42种分法

0 请登录后投票
   发表时间:2011-08-07  
5的情况,实际上只有7种:
1 1 1 1 1
1 1 1 2
1 2 3
1 4
2 2 1
2 3
5

其实这个问题可以拆解为将 N元钱化成1,2...N-1,N 元硬币(其中有些硬币是假想出来的)的组合问题,比如将5元钱化成1,2,3,4,5的硬币组合
代码如下:
int[] a = new int[] { 1,2,3,4,5};
		int[] b = new int[6];
		int[] c = new int[6];

		System.out.println(System.currentTimeMillis());
		Arrays.fill(b, 1);
		for (int i = 1; i < a.length; i++) {
			for (int j = 1; j * a[i] <= 5; j++) {
				for (int k = 0; k + j * a[i] <= 5; k++)
					c[k + j * a[i]] += b[k];

			}
			for (int k = 1; k <= 5; k++) {
				b[k] += c[k];
				c[k] = 0;
			}
		}
		System.out.println("totally " + b[5] + " solutions.");
		System.out.println(System.currentTimeMillis());


呵呵,这个算法估计一般人是看不懂了,
给一个用递归实现的:
private static final int[] COINS = new int[] { 1, 2, 3, 4, 5};
         
         private static int SUM = 5;

	private static int count = 0;

	public static void main(String[] args) throws Exception {
		System.out.println(System.currentTimeMillis());
		calc(SUM, COINS.length-1, "");
		System.out.println("totally " + count + " solutions. ");
		System.out.println(System.currentTimeMillis());
	}

	private static void calc(int sum, int coinIdex, String pre) {
		if (sum <= 0) {
			if (sum == 0) {
				count++;
			}
		}
		for (int i = coinIdex; i >= 0; i--) {
			if (sum >= 0) {
				calc(sum - COINS[i], i, pre + " " + COINS[i]);
			}
		}
	}


对这类问题可以参考我的博客最近总结的“硬币分钱”问题http://hxz-qlh.iteye.com/
0 请登录后投票
   发表时间:2011-08-09  
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());
		}
	}
}


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


过程中 最后一个循环改成这样  不知有么有更好 。
for (int k = 0; k <=(i-j>j?j:i-j); k++) {
	dp[i][j] += dp[i - j][k];
}


0 请登录后投票
论坛首页 综合技术版

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