【区间动规】【记忆化搜索】[NOI1995]石子合并
题目:[NOI1995]石子合并 rqnoj490
题目描述
在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.
输入格式
数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.
输出格式
输出共2行,第1行为最小得分,第2行为最大得分.
样例输入
样例输出
动规 f[i,j]表示区间[i,j]
f[i,j]=max{f[i,j],f[i,k]+f[k+1,j]+i 到 j 的总和,...} k从i到j-1循环
如果嫌递推麻烦的话可以记忆化搜索,很简单的
Pascal Code
program rqnoj490; var n:longint; a,s:array[0..200+10] of longint; f:array[0..200+10,0..200+10] of longint; procedure init; begin assign(input,'rqnoj490.in'); assign(output,'rqnoj490.out'); reset(input); rewrite(output); end; procedure outit; begin close(input); close(output); halt; end; procedure readdata; var i:longint; begin read(n); for i:=1 to n do begin read(a[i]); a[i+n]:=a[i]; end; for i:=1 to 2*n do s[i]:=s[i-1]+a[i]; end; function sum(i,j:longint):longint; begin if i<=j then exit(s[j]-s[i-1]) else exit(s[j+n]-s[i-1]); end; function min(i,j:longint):longint; var k:longint; begin if f[i,j]<>$07070707 then exit(f[i,j]); if i=j then exit(0); for k:=i to j-1 do begin if f[i,j]>min(i,k)+min(k+1,j)+sum(i,j) then f[i,j]:=min(i,k)+min(k+1,j)+sum(i,j); end; exit(f[i,j]); end; function max(i,j:longint):longint; var k:longint; begin if f[i,j]<>0 then exit(f[i,j]); if i=j then exit(0); for k:=i to j-1 do begin if f[i,j]<max(i,k)+max(k+1,j)+sum(i,j) then f[i,j]:=max(i,k)+max(k+1,j)+sum(i,j); end; exit(f[i,j]); end; procedure main; var ans,i,j:longint; begin ans:=maxlongint; fillchar(f,sizeof(f),$7); for i:=1 to n do if ans>min(i,i+n-1) then ans:=min(i,i+n-1); writeln(ans); ans:=0; fillchar(f,sizeof(f),0); for i:=1 to n do if ans<max(i,i+n-1) then ans:=max(i,i+n-1); writeln(ans); end; begin init; readdata; main; outit; end.
..... 转载请注明出处 ..... http://oijzh.cnblogs.com ..... by jiangzh