复制书稿(动规例题)

题目大意:把n个数分为连续的k段,使得每一段的最大值最小(如果多解,则前面段的数越少越好,即后面段的数越多越好)


样例输入:

9 3

1 2 3 4 5 6 7 8 9

样例输出:

1 5

6 7

8 9


输出表示把n个数如何分段,每一段的开头st和结尾en。


这道题目可以用dp的方法,设f[i,j]表示前i个数分为j段的最优值。

f[i,j]的状态转移方程显然是非常简单的,注意初始值设定为f[1,j]:=d[j](1<=j<=m,d[j]=d[j-1]+a[j])。然后这道题还需注意的就是输出。

输出需要用贪心的算法。首先因为题目说了如果有多解,要求后面的段多数字,那么因为我们输出都是从后往前逆推的,所以我们直接就判断如果后面的段能继续装下数字且不超过最优值就一直装,当不能装的时候就再判断下一段,以此类推,可以用递归输出,更加的好处理。


代码:

var
        i,j,m,n,k:Longint;
        a,b:Array[0..500] of Longint;
        f:array[0..500,0..500] of Longint;
function max(x,y:Longint):Longint;
begin
        if x>Y then exit(x); exit(y);
end;
function min(x,y:Longint):Longint;
begin
        if x<Y then exit(x); exit(y);
end;
procedure print(i,j:Longint);
var
        t,x:Longint;
begin
        if j=0 then exit;
        if j=1 then
        begin
                writeln(1,' ',i);
                exit;
        end;
        t:=i;
        x:=a[i];
        while x+a[t-1]<=f[n,m] do
        begin
                x:=x+a[t-1];
                t:=t-1;
        end;
        print(t-1,j-1);
        writeln(t,' ',i);
end;
begin
        readln(m,n);
        fillchar(f,sizeof(f),$7f);
        for i:=1 to m do
        begin
                read(a[i]);
                b[i]:=b[i-1]+a[i];
                f[1,i]:=b[i];
        end;
        for i:=2 to n do
                for j:=i to m do
                        for k:=1 to j-1 do
                                f[i,j]:=min(max(f[i-1,k],b[j]-b[k]),f[i,j]);
        print(m,n);
end.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值