[动态规划]花店橱窗 线性动归

背景 Background
xq和他的老婆xz最近开了一家花店,他们准备把店里最好看的花都摆在橱窗里。但是他们有很多花瓶,每个花瓶都具有各自的特点,因此,当各个花瓶中放入不同的花束时,会产生不同的美学效果。为了使橱窗里的花摆放的最合适,他们得想个办法安排每种花的摆放位置。
可是因为xq和xz每天都太忙,没有时间设计橱窗里花的摆法,所以他们想让你帮他们求出花摆放的最大美观程度和每种花所放的位置。


描述 Description
每种花都有一个标识,假设杜鹃花的标识数为1,秋海棠的标识数为2,康乃馨的标识数为3,所有的花束在放入花瓶时必须保持其标识数的顺序,即:杜鹃花必须放在秋海棠左边的花瓶中,秋海棠必须放在康乃馨左边的花瓶中。如果花瓶的数目大于花束的数目。则多余的花瓶必须空置,且每个花瓶中只能放一束花。

每种花放在不同的瓶子里会产生不同的美观程度,美观程度可能是正数也可能是负数。

上述例子中,花瓶与花束的不同搭配所具有的美观程度,如下表所示:

花 瓶

1 2 3 4 5
1 (杜鹃花) 7 23 -5 -24 16
2 (秋海棠) 5 21 -4 10 23
3 (康乃馨) -21 5 -4 -20 20


根据上表,杜鹃花放在花瓶2中,会显得非常好看;但若放在花瓶4中则显得十分难看。

为取得最大美观程度,你必须在保持花束顺序的前提下,使花束的摆放取得最大的美学值,并求出每种花应该摆放的花瓶的编号。
输入格式 Input Format
第1行:两个整数F和V,表示xq和xz一共有F种花,V个花瓶。(1<=F<=V<=100)
第2行到第F+1行:每行有V个数,表示花摆放在不同花瓶里的美观程度值value。(美观程度和不超过maxint,美观程度有正有负。)
输出格式 Output Format
输出有两行:第一行为输出最大美观程度和的值,第二行有F个数表示每朵花应该摆放的花瓶的编号。
样例输入 Sample Input [复制数据]

样例输出 Sample Output [复制数据]

时间限制 Time Limitation

各个测试点1s


简单的线性动归。

f[i,j]表示前i种花,第i种花放在第j个花瓶里的最大值。

则只需要枚举k作为前一种花所放的花瓶。

f[i,j]=max(f[i-1,k]+a[i,j])  i-1<=k<=j-1


如何构造这个解,类比于算导。

如果f[i,j]被更新,那么g[i,j]表示上一次的k

递归求出解


var i,j,k,n,m,ans,tot:longint;
    f,a,g:array[-20..120,-20..120]of longint;
    s:array[-20..120]of longint;
function max(a,b:longint):longint;
begin
    if a>b then exit(a) else exit(b);
end;

procedure work(i,j:longint);
begin
    if i<0 then exit;
    s[tot]:=j;
    dec(tot);
    work(i-1,g[i,j]);
end;

begin
    fillchar(g,sizeof(g),0);
    fillchar(f,sizeof(f),-$7f);
    readln(n,m);
    for i:=1 to m do
    f[0,i]:=0;tot:=0;
    for i:=1 to n do
    for j:=1 to m do
    read(a[i,j]);

   for i:=1 to n do
    begin
       tot:=tot+a[i,i];
       f[i,i]:=tot;
    end;
    for i:=1 to n do
    for j:=i to m do
    begin
        for k:=i-1 to j-1 do
        begin
          if f[i,j]<f[i-1,k]+a[i,j] then g[i,j]:=k;
          f[i,j]:=max(f[i,j],f[i-1,k]+a[i,j]);
        end;
    end;

    ans:=0;
    for i:=1 to m do
    if ans<f[n,i] then ans:=f[n,i];
    tot:=n;
    for i:=1 to m do
    begin
        if f[n,i]=ans then
        begin
            k:=i;
            break;
        end;
    end;
    work(n,k);
    writeln(ans);
    for i:=1 to n do write(s[i],' ');
    readln;readln;
end.








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值