两道很不错的dp
3186很神似回文词,合并石子之类的问题;
一开始不知道怎么在dp方程中体现权值天数,很来才想起来
对于一段区间[i,j],里面的东西必然是要卖完的
又因为只能从两头开始卖,所以
dp[i,j]=max(dp[i+1,j],dp[i,j-1])+sum[i,j];
这样就体现出先后卖的差别;
最后答案很显然是dp[1,n];
而poj3267,dp方程不好讲,直接上代码;
1 var f:array[0..1000,0..500] of longint; 2 b,a,sa,sb:array[0..500] of longint; 3 p,y,q,i,j,k,n,m:longint; 4 function max(a,b:longint):longint; 5 begin 6 if a>b then exit(a) else exit(b); 7 end; 8 9 begin 10 readln(m,n); 11 for i:=1 to n do 12 begin 13 readln(b[i],a[i]); 14 sa[i]:=sa[i-1]+a[i]; 15 sb[i]:=sb[i-1]+b[i]; 16 end; 17 f[1,0]:=0; 18 i:=1; 19 while i<=2*n+1 do 20 begin 21 inc(i); 22 f[i,0]:=f[i-1,0]; 23 for j:=1 to n do 24 begin 25 if f[i-1,j]=0 then break; 26 f[i,0]:=max(f[i,0],f[i-1,j]); 27 end; 28 for j:=1 to n do 29 begin 30 for k:=0 to n do 31 begin 32 if (f[i-1,k]=0) and (k<>0) then break; //后面的状态不存在,直接退 33 p:=f[i-1,k]; 34 q:=f[i-1,k]+j; 35 if q>n then continue; 36 y:=f[i-1,k]-k; 37 if (sb[q]-sb[p]+sa[p]-sa[y]<=m) and (sa[q]-sa[p]<=m) then //判断是否够这个月花的 38 f[i,j]:=max(f[i,j],f[i-1,k]+j); 39 end; 40 if f[i,j]>=n then 41 begin 42 writeln(i+1); //注意付完款一定是下个月 43 halt; 44 end; 45 if f[i,j]=0 then break; 46 end; 47 end; 48 end.