P1854 花店橱窗布置

题目描述

某花店现有$F$束花,每一束花的品种都不一样,同时至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定的,从左到右按$1$到$V$顺序编号,$V$是花瓶的数目。花束可以移动,并且每束花用$1$到$F$的整数标识。如果$I < J$,则花束$I$必须放在花束$J$左边的花瓶中。例如,假设杜鹃花的标识数为$1$,秋海棠的标识数为$2$,康乃馨的标识数为$3$,所有花束在放入花瓶时必须保持其标识数的顺序,即杜鹃花必须放在秋海棠左边的花瓶中,秋海棠必须放在康乃馨左边的花瓶中。如果花瓶的数目大于花束的数目,则多余的花瓶必须空,即每个花瓶只能放一束花。

每个花瓶的形状和颜色也不相同,因此,当各个花瓶中放入不同的花束时,会产生不同的美学效果,并以美学值(一个整数)来表示,空置花瓶的美学值为0。在上述的例子中,花瓶与花束的不同搭配所具有的美学值,可以用如下的表格来表示:

花瓶1 花瓶2 花瓶3 花瓶4 花瓶5

杜鹃花 $7\  23\  -5\  -24\  16$

秋海棠 $5\  21\  -4\  10\  23$

康乃馨 $-21\  5\  -4\  -20\  20$

根据表格,杜鹃花放在花瓶$2$中,会显得非常好看,但若放在花瓶$4$中,则显得很难看。

为了取得最佳的美学效果,必须在保持花束顺序的前提下,使花的摆放取得最大的美学值,如果具有最大美学值的摆放方式不止一种,则输出任何一种方案即可。

输入格式

输入文件的第一行是两个整数$F$和$V$,分别为花束数和花瓶数$(1\leqslant F\leqslant 100,F\leqslant V\leqslant 100)$。接下来是矩阵$A_{i,j}$,它有$I$行,每行$J$个整数,$A_{i,j}$表示花束$I$摆放在花瓶$J$中的美学值。

输出格式

输出文件的第一行是一个整数,为最大的美学值;接下来有F行,每行两个数,为那束花放入那个花瓶的编号。

样例数据

输入

3 5
7 23 -5 -24 16
5 21 -4 10 23
-21 5 -4 -20 20

输出

53
2 4 5

分析

因为题中说当前插花的花瓶在上一个插花的花瓶以后,很容易想到数字三角形。那么原题就可以变为在一个矩阵中只能向右下走,求经过的矩阵元素的和的最大值。最后递归输出路径。注意,初始化$Dp=INF,Dp_{0,i}=0$,状态转移方程$$Dp_{i,j}=max\left \{Dp_{i,j},Dp_{i-1,k-1}+G_{i,k}\right \}$$

代码

#include <bits/stdc++.h>

#define Enter puts("")
#define Space putchar(' ')
#define INF 1e9

using namespace std;

typedef long long ll;
typedef double Db;

inline ll Read()
{
    ll Ans = 0;
    char Ch = getchar() , Las = ' ';
    while(!isdigit(Ch))
    {
        Las = Ch;
        Ch = getchar();
    }
    while(isdigit(Ch))
    {
        Ans = (Ans << 3) + (Ans << 1) + Ch - '0';
        Ch = getchar();
    }
    if(Las == '-')
        Ans = -Ans;
    return Ans;
}

inline void Write(ll x)
{
    if(x < 0)
    {
        x = -x;
        putchar('-');
    }
    if(x >= 10)
        Write(x / 10);
    putchar(x % 10 + '0');
}

int G[105][105];
int Dp[105][105];

void Print(int i , int j)
{
    if(i == 0)
        return;
    int n = i;
    while(Dp[i][n] != j)
        n++;
    Print(i - 1 , j - G[i][n]);
    Write(n) , Space;
}

signed main()
{
    int f = Read() , v = Read();
    for(int i = 1; i <= f; i++)
        for(int j = 1; j <= v; j++)
            G[i][j] = Read();
    memset(Dp , 128 , sizeof(Dp));
    for(int i = 0 ; i <= 101; i++)
        Dp[0][i] = 0;
    for(int i = 1; i <= f; i++)
        for(int j = i; j <= v - f + i; j++)
            for(int k = 1; k <= j; k++)
                Dp[i][j] = max(Dp[i][j] , Dp[i - 1][k - 1] + G[i][k]);
    Write(Dp[f][v]) , Enter;
    Print(f , Dp[f][v]);
    return 0;
}

/*
3 5
7 23 -5 -24 16
5 21 -4 10 23
-21 5 -4 -20 20
*/

 

posted @ 2021-06-19 18:38  Tenderfoot  阅读(77)  评论(0编辑  收藏  举报