vijos p1117(数的划分)(100)
我想说,题目的意思有误啊!!!!
他说任意两份不能相同,我就以为分成的每个部分都不能相同...但他的意思是这是个组合,不是排列(即不考虑顺序问题....)
被坑了.....
算法: 递归+记忆化搜索
顺便说一下 个人比较喜欢用 haha来作为函数的名称.....
ans:=haha(n,k,min). 意思是从 把n 分成 k份的方案数,至于后面的1。意思是分出来的每份的值小于min(初始值为1),这个东西在后面有用。
因为我们要得出的是一个组合,不是排列,所以我们可以设每次的方案分出的数的序列都是一个不降的序列,如此就有:
当k>=2 时,我们有haha(n,k,min):=haha(n,k,min)+haha(n-i,k-1,i);如果其中(min<=i<=n).
当k=1 时, haha(n,k,min):=1;(分成一份当然只有一种方案)。
优化:递归的缺点就是有很多重复的计算,所以我们可以另开一个三维数组来记录每一次函数的值,如果再需计算这个函数,我们先检查这个函数是否已经在数组里记录过了,如果已经记录,直接调用数组,否则再计算函数。
代码:
1 program p1117; 2 var 3 i,j,k,l,m,n:longint; 4 ha:array[0..200,0..6,0..200]of longint; 5 function haha(n,k,min:longint):longint; 6 var 7 i,j:longint; 8 begin 9 haha:=0; 10 if k=1 then 11 begin 12 if n<min then haha:=0 13 else begin haha:=1; ha[n,k,min]:=1; end; 14 end 15 else 16 for i:=min to n do 17 begin 18 if ha[n-i,k-1,i]<>0then 19 haha:=haha+ha[n-i,k-1,i] 20 else haha:=haha+haha(n-i,k-1,i); 21 end; 22 ha[n,k,min]:=haha; 23 end; 24 begin 25 fillchar(ha,sizeof(ha),0); 26 read(n,k); 27 m:=haha(n,k,1); 28 write(m); 29 end.
还要加油啊!