两道很不错的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.
View Code

 

posted on 2014-01-21 22:56  acphile  阅读(113)  评论(0编辑  收藏  举报