动态规划练习题(1)

1、0/1背包(package.pas)

AYYZOJ p1472

 1 program p1472;
 2 const
 3   maxm=200; maxn=30;
 4 var
 5   m,n,i,j:integer;
 6   c,w:array[1..maxn] of integer;
 7   f:array[0..maxn,0..maxm] of integer;
 8 function max(x,y:integer):integer;
 9 begin
10   if x>y then max:=x else max:=y;
11 end;
12 begin
13   readln(m,n);
14   for i:=1 to n do readln(w[i],c[i]);
15   for i:=1 to n do
16    for j:=1 to m do
17     begin
18       if j>=w[i] then f[i,j]:=max(f[i-1,j-w[i]]+c[i],f[i-1,j])
19         else f[i,j]:=f[i-1,j];
20     end;
21  writeln(f[n,m]);
22 end.
参考程序

2、采药(medic.pas)

AYYZOJ p1052

COGS p68

 1 const
 2   maxm=1000; maxn=100;
 3 var
 4   f:array[0..maxn,0..maxm] of integer;
 5   w,c:array[1..maxn] of integer;
 6   m,n,i,j:integer;
 7 
 8 function max(x,y:integer):integer;
 9 begin
10   if x>y then max:=x else max:=y
11 end;
12 
13 begin
14 assign(input,'medic.in');
15 reset(input);
16 assign(output,'medic.out');
17 rewrite(output);
18   readln(m,n);
19   for i:=1 to n do readln(w[i],c[i]);
20   fillchar(f,sizeof(f),0);
21    for i:=1 to n do
22     for j:=1 to m do
23      if j>=w[i] then f[i,j]:=max(f[i-1,j-w[i]]+c[i],f[i-1,j])
24                else f[i,j]:=f[i-1,j];
25   writeln(f[n,m]);
26 close(input);
27 close(output);
28 end.
参考程序

3、开心的金明(happy.pas)

AYYZOJ p1059

COGS p71

 1 var
 2   f:array[0..30000] of longint;
 3   w,c:array[1..30000] of longint;
 4   i,j,m,n,ans:longint;
 5 begin
 6 assign(input,'happy.in');
 7 reset(input);
 8 assign(output,'happy.out');
 9 rewrite(output);
10   readln(m,n);
11   for i:=1 to n do readln(w[i],c[i]);
12   fillchar(f,sizeof(f),0);
13    for i:=1 to n do
14     for j:=m downto w[i] do
15      if f[j-w[i]]+c[i]*w[i]>f[j] then f[j]:=f[j-w[i]]+c[i]*w[i]
16       else f[j]:=f[j]+c[j]*w[j];
17    writeln(f[m]);
18 close(input);
19 close(output);
20 end.
参考程序1
 1 var
 2   n,m,i,j:integer;
 3   v,p:array[1..25] of longint;
 4   dp:array[0..30000] of longint;
 5   function max(x,y:longint):longint;
 6   begin if x>y then max:=x else max:=y; end;
 7 begin
 8   assign(input,'happy.in'); assign(output,'happy.out');
 9   reset(input); rewrite(output);
10   readln(n,m);
11   for i:=1 to m do
12     begin
13       readln(v[i],p[i]);
14       p[i]:=p[i]*v[i];
15     end;
16   for i:=1 to m do
17     for j:=n downto v[i] do
18       dp[j]:=max(dp[j],dp[j-v[i]]+p[i]);
19   writeln(dp[n]);
20   close(input); close(output);
21 end.
参考程序2

4、装箱问题(box.pas)

AYYZOJ p1021

COGS p1089

我的思路:使剩余空间最小,则可以设每件物品的价值c[i]=每件物品的体积w[i] 。转化为0/1背包问题,最后输出V-dp[v]即可

 1 var
 2   v,n,i,j:longint;
 3   w,c:array[1..30] of longint;
 4   dp:array[0..20000] of longint;
 5 function max(x,y:longint):longint;
 6 begin
 7   if x>y then max:=x else max:=y;
 8 end;
 9 begin
10 assign(input,'npack.in');
11 reset(input);
12 assign(output,'npack.out');
13 rewrite(output);
14   readln(v);
15   readln(n);
16   for i:=1 to n do begin readln(w[i]); c[i]:=w[i]; end;
17    for i:=1 to n do
18     for j:=v downto w[i] do
19      dp[j]:=max(dp[j-w[i]]+c[i],dp[j]);
20    writeln(v-dp[v]);
21 close(input);
22 close(output);
23 end.
我的程序

另一种思路:{f[j]是布尔数组,表示前i件物品正好装满容积为j的箱子,最后从后往前扫描布尔数组f,找到最大值}

 1 var
 2  f:array [0..20000] of boolean;
 3  box:array [0..30] of integer;
 4  n,v,m,i,j:longint;
 5 begin
 6  readln(v);
 7  readln(n);
 8  for i:=1 to n do read(box[i]);
 9  for i:=0 to v do f[i]:=false;
10  f[0]:=true;
11  for i:=1 to n do
12    for j:=v downto box[i] do
13      if f[j-box[i]] then f[j]:=true;
14  for i:=v downto 0 do if f[i]=true then
15    begin
16       writeln(v-i);
17       halt;
18    end;
19 end.
老师给的程序

5、竞赛真理(truth.pas/c/cpp)

AYYZOJ p1493

 1 var
 2   n,t,i,j:longint;
 3   f:array[0..1080000] of longint;
 4   w1,t1,w2,t2:array[0..30] of longint;
 5 function max(a,b:longint):longint;
 6 begin
 7   if a>b then max:=a
 8    else max:=b;
 9 end;
10 begin
11   fillchar(f,sizeof(f),0);
12   readln(n,t);
13   for i:=1 to n do
14    readln(w1[i],t1[i],w2[i],t2[i]);
15   for i:=1 to n do
16    for j:=t downto 1 do
17    begin
18      if j>=t1[i] then
19       f[j]:=max(f[j-t1[i]]+w1[i],f[j]);
20      if j>=t2[i] then
21       f[j]:=max(f[j-t2[i]]+w2[i],f[j]);
22    end;
23   writeln(f[t]);
24 end.
我的程序
 1 var a,b:array[1..30,1..2] of longint;
 2     f:array[0..1080000] of longint;
 3     i,j,n,time:longint;
 4 begin
 5   readln(n,time);
 6   for i:=1 to n do
 7     read(a[i,1],b[i,1],a[i,2],b[i,2]);
 8   for i:=1 to n do
 9     for j:=time downto 1 do begin
10       if j>=b[i,1] then
11         if f[j]<f[j-b[i,1]]+a[i,1] then f[j]:=f[j-b[i,1]]+a[i,1];
12       if j>=b[i,2] then
13         if f[j]<f[j-b[i,2]]+a[i,2] then f[j]:=f[j-b[i,2]]+a[i,2];
14     end;
15   writeln(f[time]); 
16 end.
老师给的程序

 【问题分析】

本题是背包问题的应用,可用动态规划来做,设 f(i,x)表示前i道题,总时间不超过x的最大得分则动态转移方程为:

    f(i,x)=max(f(i-1,x-T1[i])+W1[i] ,f(i-1,x-T2[i])+W2[i],f(i-1,x))

f(n,t)即为最优解,边界条件为f(0,x)=0 ,f(i,0)=0;

由于这道题目中给出的时间T的取值较大达到1080000,如果定义成二维数组即使在Free Pascal中也无法实现,我们不妨把f(n,t)定义成两个一维数组f1(i)和f2(i),由于上次的计算结果只对当前的计算有用,所以我们把这两个数组迭代使用,直到计算出最后的结果。

 1 【参考程序】1 2 program truth;
 3   const maxn=30;maxt=1080000;
 4   var
 5     total,n,k,i,j:longint;
 6     t1,t2,w1,w2:array[1..maxn] of longint;
 7     f1,f2:array[0..maxt] of longint;
 8     fw:array[0..maxt] of longint;
 9   function max(a,b,c:longint):longint;
10     begin
11       if a<b then a:=b;
12       if a<c then a:=c;
13       max:=a;
14     end;
15   function max2(a,b:longint):longint;
16     begin
17       if a<b then a:=b;
18       max2:=a;
19     end;
20   begin
21     assign(input,'truth.in');
22     reset(input);
23     assign(output,'truth.out');
24     rewrite(output);
25     readln(n,k);
26     for i:=1 to n do
27       readln(w1[i],t1[i],w2[i],t2[i]);
28     fillchar(f1,sizeof(f1),0);
29     fillchar(f2,sizeof(f2),0);
30     for i:=1 to n do
31      begin
32       for j:=1 to k do
33         if (j>=t1[i]) and (j>=t2[i])
34           then f2[j]:=max(f1[j-t1[i]]+w1[i],f1[j-t2[i]]+w2[i],f1[j])
35           else
36             if j>=t1[i] then f2[j]:=max2(f1[j-t1[i]]+w1[i],f1[j])
37               else if j>=t2[i] then f2[j]:=max2(f1[j-t2[i]]+w2[i],f1[j])
38                      else f2[j]:=f1[j];
39       for j:=0 to k do f1[j]:=f2[j];
40      end;
41     writeln(f2[k]);
42     close(output);
43     close(input)
44   end.
45 【参考程序】2
46 var a,b:array[1..30,1..2] of longint;
47     f1:array[0..600000] of longint;
48     i,j,n,time:longint;
49 begin
50   assign(input,'truth.int');reset(input);
51 assign(output,'truth.out');rewrite(output);
52   readln(n,time);
53   for i:=1 to n do
54     read(a[i,1],b[i,1],a[i,2],b[i,2]);
55   for i:=1 to n do
56     for j:=time downto 1 do begin
57       if j>b[i,1] then
58         if f1[j]<f1[j-b[i,1]]+a[i,1] then f1[j]:=f1[j-b[i,1]]+a[i,1];
59       if j>b[i,2] then
60         if f1[j]<f1[j-b[i,2]]+a[i,2] then f1[j]:=f1[j-b[i,2]]+a[i,2];
61      { f1:=f2;}
62     end;
63   writeln(f1[time]); 
64 
65 end. 
66 
67 参考程序3:
68 var
69     i,j,n,t:longint;
70     v1,w1,v2,w2:array[1..30]of longint;
71     f:array[0..1080000]of longint;
72 begin
73     assign(input,'truth.in');
74     reset(input);
75     assign(output,'truth.out');
76     rewrite(output);
77     readln(n,t);
78     for i:=1 to n do read(v1[i],w1[i],v2[i],w2[i]);
79     for i:=1 to n do
80         for j:=t downto 0 do begin
81             if(j>=w1[i])and(f[j-w1[i]]+v1[i]>f[j])then f[j]:=f[j-w1[i]]+v1[i];
82             if(j>=w2[i])and(f[j-w2[i]]+v2[i]>f[j])then f[j]:=f[j-w2[i]]+v2[i];
83         end;
84     writeln(f[t]);
85     close(input);
86     close(output);
87 end.
参考程序
原文地址:https://www.cnblogs.com/vacation/p/5404156.html