在csdn上看到一个很有意思的算法问题,看看谁的算法最简单(100分)

  • 主题发起人 主题发起人 yanlei
  • 开始时间 开始时间
Y

yanlei

Unregistered / Unconfirmed
GUEST, unregistred user!
给定两个正整数m,n(m>=n!),将m拆成n个数相加:m=a(1)+a(2)+...+a(n),使之满足:a(1)<a(2)<...<a(n);
编成列出所有的拆法.
例如:若m=7,n=3则只有一种拆法:
7=1+2+4
 
已知m,n(m>=n!,m>0,n>0),求分解? 好像以前在哪本数学竞赛书上见过!
思路嘛?!
令i:=m-n*(n-1)/2,那么只要做一个 1 ... i 的全排列即可!
为上面的 1 ... i 定义一个数组 T
然后将上面的 i 个数中取 n 个的组合全罗列出来,凡是取出的组合中的数之和不为 m 的就舍去。
呵呵!剩下的就是你要的了!
回头看看,随手写的,想得简单,写得粗糙,有很多地方还是可以优化的!
敬请大家斧正!^_^
 
最好有原码,加解释
 
这个问题,我昨天已经用vc和delphi都答过了,这次既然有分,我就来一次:)
program Project2;
{$APPTYPE CONSOLE}
uses SysUtils;
const
M=20;
N=4;
var
Num:Array[0..N-1] of Integer;//定义数组,记录数列
//定义回调函数,SumNum为已经遍历的数的和,l为第几个数,初值为1,
//m,n为题目给的条件
Procedure GetNum(SumNum:Integer;
m:Integer;n:Integer;l:Integer);
var
i,j:Integer;
begin
for i:=l to m-ndo
begin
if ((l>1) and (i<=Num[l-2])) then
//如果为第1个以后的数,且值小于前面的,就继续
continue;
Num[l-1]:=i;
//记录该数
if (l<>n) then
//如果l<> n,以(sumNum+i,l+1)继续循环。
GetNum(SumNum+i,m,n,l+1)
else
//如果等于,判断sumNum+i是否等于m,如相等,打印该数列
if (m=(SumNum+i)) then
begin
for j:=0 to n-1do
begin
write(Num[j]);
write(' ');
end;
writeln('');
end;
end;
end;

begin
GetNum(0,M,N,1);
readln;
end.
更大的数我就没测试了,可能会堆栈溢出
 
后退
顶部