3.solve(solve.pas/c/cpp)
描述
dsqwwe每个月都有m(0<=m<=1000)元的零花钱,他现在有n(n<=300)项消费计划,每个消费计划消耗2种费用,一种是要花掉当前月的零花钱,另一种是要花掉下一个月的零花钱,每个月的零花钱不能超支,若一个月的零花钱不能用完,dsqwwe会把钱花在其他地方,也就是说,每个月剩余的零花钱不会留给下一个月。问dsqwwe想要完成他所有的消费计划最少需要几个月。
计划要顺序完成。
输入(solve.in):
第一行:m,n
接下来的n行,每行两个整数a,b,描述一种消费计划,a代表花掉当前月的钱的数目,b代表花掉下个月的钱的数目(a,b<=m)
输出(solve.out):
需要最少的月数
样例输入:
100 5
40 20
60 20
30 50
30 50
40 40
样例输出:
5
样例解释:
+------+-------+--------+---------+---------+--------+
| |零花钱 |解决问题| 当前支付| 下月预支|月底结余|
|月份 | | | | | |
+------+-------+--------+---------+---------+--------+
| 1 | 100 | 1, 2 | 40+60 | 0 | 0 |
| 2 | 100 | 3, 4 | 30+30 | 20+20 | 0 |
| 3 | 100 | -none- | 0 | 50+50 | 0 |
| 4 | 100 | 5 | 40 | 0 | 60 |
| 5 | 100 | -none- | 0 | 40 | 60 |
+------+-------+--------+---------+---------+--------+
DP 。
首先,开 f[i,j] 表示前 i 个月做 j 个任务,最后一个月所能最多剩下的钱。
然后,分析,枚举最后一个月做了最后 k 个任务,然后判断,也就是,这 k 个任务可以压缩到 2 个月来完成而不会预支,也就是总钱数在 m 以下,然后,取最大值转移。
2 维的 DP 。
program liukeke;
var
a,b:array[0..301] of longint;
f:array[0..601,0..301] of longint;
x1,x2,n,m,i,j,k,ans:longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a);
exit(b);
end;
begin
assign(input,'solve.in');reset(input);
assign(output,'solve.out');rewrite(output);
readln(m,n);
for i:=1 to n do
begin
readln(x1,x2);
a[i]:=a[i-1]+x1;
b[i]:=b[i-1]+x2; // a,b 为 累和。
end;
fillchar(f,sizeof(f),128);
f[0,0]:=m;
while true do
begin
inc(ans);
for j:=1 to n do
for k:=0 to j do
if (f[ans-1,k]>=a[j]-a[k])and(m>=(b[j]-b[k])) then
begin
f[ans,j]:=max(f[ans,j],m-(b[j]-b[k]));
if f[ans,j]=m then break; //不能更大值了
end;
if f[ans,n]>=0 then break; //做完了
end;
writeln(ans+1); //最后一拨任务影响的是两个月。
close(input);
close(output);
end.