一道简单的编程题,让我想到了很多...
题目不算难,可能是我比较笨吧,它让我思考了好久,大概描述如下:
将正整数m分解为n个正整数之和,且分解后的数成降序排列
例如:将8(m=8)分解为4(n=4)个正整数之和,要求程序输出结果为
5 1 1 1; 4 2 1 1; 3 2 2 1 ......
输出所有的可能性
开始时我根据由个别到一般的思路,先用较小的数字试验,这样一来可以总结规律,二来便
于验算输出结果的正确性。经过几轮的试验,我渐渐看出了循环的规律,主要是记数变量的初值
和终止条件的问题,还有判断条件(使正解输出)的问题。
[v1.0.0.0代码]
/**
*NAME:pcw_09Demo1.java
*AUTHOR:Richard
*DATE:Mar-16,2006
*VERSION:1.0.0.0
*/
import java.io.*;
public class pcw_09Demo1{
public static void main(String[] args) throws IOException{
int m = 9; //要被分解的整数
int n = 3; //要分解成的整数个数
int[] result = new int[4]; //用来存储结果
//core code
//#############################################################################
for(int i=m-(n-1); i>=m/n; i--)
{
result[0] = i;
for(int j=m-(n-1)-(n-2); j>=1; j--)
{
result[1] = j;
for(int k=m-(n-1)-(n-2)-(n-3); k>=1; k--)
{
result[2] = k;
//判断条件,符合条件者输出
if((result[0]>=result[1]) &&
(result[1]>=result[2]) &&
((result[0]+result[1]+result[2])==m))
{
System.out.println("-" +result[0]+ "-" +result[1]+ "-" +result[2]+ "-");
System.in.read();
//进入下一轮循环
}
}
}
}
//#############################################################################
//core code
}
}
这个原形出来以后我总结了循环的规律,直观的看循环的起止条件是m-(n-1);1
m-(n-1)-(n-2);1 m-(n-1)-(n-2)-(n-3);1 ……依次类推可到n的可能,化简上式可得
m-n+1;1 m-2n+3;1 m-3n+6;1 ……这为我们用递归来描述这个问题提供了方便,所谓有规
律好办事,我想这也是计算机专业数学课多的一个原因吧。在进行这个之前,我先要把输出和判
断条件变为适应n的可能,所以我对代码做了如下的部分修改,测试这两个部分的正确性,毕竟
使用一个熟悉的框架要省去很多麻烦事。
[v1.0.0.2代码]
/**
*NAME:pcw_09Demo2.java
*AUTHOR:Richard
*DATE:Mar-16,2006
*VERSION:1.0.0.2
*/
/**
*将输出部分和求和判断条件作了调整,使之能够适应推广到任意数的可能
*/
import java.io.*;
public class pcw_09Demo{
public static void main(String[] args) throws IOException{
int m = 12; //要被分解的整数
int n = 3; //要分解成的整数个数
int[] result = new int[n]; //用来存储结果
//core code
//######################################################################
for(int i=m-(n-1); i>=m/n; i--)
{
result[0] = i;
for(int j=m-(n-1)-(n-2); j>=1; j--)
{
result[1] = j;
for(int k=m-(n-1)-(n-2)-(n-3); k>=1; k--)
{
result[2] = k;
//判断条件,符合条件者输出
int sum = 0;
for(int p=0; p<n; p++) //求和
sum += result[p];
if((result[0]>=result[1]) && (result[1]>=result[2]) && (sum==m))
{
for(int q=0; q<n; q++)
System.out.print("-" +result[q]+ "-");
System.out.println();
System.in.read();
//进入下一轮循环
}
}
}
}
//######################################################################
//core code
}
}
今天和网上喜欢编程的朋友讨论了一番,受益匪浅,第一次意识到这个问题竟然是个典型的
“背包问题”的变形,他的分析能力确实挺强,他把问题分解成了“背包问题”和后期对数组的
排序两个部分,这点是值得我学习的。还有一件有趣的事,他上网找到的分析竟然是我写的,我
第一次真正感觉到网络是我们这个世界变得如此之小,变成了一个地球村。
今天先写到这,该听英语了,剩下的部分明天再想。