noip2001-数的划分 2008.11.5
心得:本以为搜索过不了,只有dp可以ac,实际上,搜索也可以过完。
如果实在想不出来dp,那就用最好的搜索来做!
法一:搜索
program sdhf;
const fin='sdhf.in';fout='sdhf.out';
var n,k,sum:longint;
f1,f2:text;
procedure search(n,k,c:longint);
var i,j:longint;
begin
if n=0 then exit;
if k=1 then begin inc(sum);exit;end;
i:=n div k;
for j:=c to i do
search(n-j,k-1,j);
end;
begin
assign(f1,fin);reset(f1);
assign(f2,fout);rewrite(f2);
read(f1,n,k);
sum:=0;
search(n,k,1);
writeln(f2,sum);
close(f1);
close(f2);
end.
法二:dp1
program sdhf;
const fin='sdhf.in';fout='sdhf.out';
var n,i,j,k,p:longint;
f:array[0..200,0..200]of longint;
f1,f2:text;
begin
assign(f1,fin);reset(f1);
assign(f2,fout);rewrite(F2);
read(f1,n,k);
fillchar(f,sizeof(f),0);
f[0,0]:=1;
for p:=1 to n do {枚举每个数}
for i:=p to n do {枚举将要拆分的数}
for j:=k downto 1 do {枚举没种分法}
inc(f[i,j],f[i-p,j-1]); {把i去掉一个p后 每种拆数相加}
writeln(f2,f[n,k]);
close(f1);close(f2);
end.
法三:dp2
分析:用f(I,j)表示将整数I分成j分的分法,可以划分为两类:
第一类 :j分中不包含1的分法,为保证每份都>=2,可以先那出j个1分到每一份,然后再把剩下的I-j分成j份即可,分法有:f(I-j,j).
第二类 : j份中至少有一份为1的分法,可以先那出一个1作为单独的1份,剩下的I-1再分成j-1份即可,分法有:f(I-1,j-1).
所以:f(I,j)= f(I-j,j)+ f(I-1,j-1)
递推公式 f(n,k) = f(n-1,k-1) + f(n-k,k)