NC51216 花店橱窗

题目链接

题目

题目描述

小q和他的老婆小z最近开了一家花店,他们准备把店里最好看的花都摆在橱窗里。

但是他们有很多花瓶,每个花瓶都具有各自的特点,因此,当各个花瓶中放入不同的花束时,会产生不同的美学效果。

为了使橱窗里的花摆放的最合适,他们得想个办法安排每种花的摆放位置。

可是因为小q和小z每天都太忙,没有时间设计橱窗里花的摆法,所以他们想让你帮他们求出花摆放的最大美观程度和每种花所放的位置。

每种花都有一个标识,假设杜鹃花的标识数为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中则显得十分难看。

为取得最大美观程度,你必须在保持花束顺序的前提下,使花束的摆放取得最大的美学值,并求出每种花应该摆放的花瓶的编号。

输入描述

第1行:两个整数F和V,表示共有F种花,V个花瓶。
第2行到第F+1行:每行有V个数,表示花摆放在不同花瓶里的美观程度值value。(美观程度和小于 \(2^{31}\) ,美观程度有正有负)

输出描述

输出有两行:第一行为输出最大美观程度和的值,第二行有F个数表示每朵花应该摆放的花瓶的编号。
若有多种方案,输出字典序较小的方案(美观程度不变的情况下,花尽量往前放)。

示例1

输入

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

输出

53
2 4 5

备注

\(1\leq F\leq V\leq 100\)

题解

知识点:线性dp。

显然dp,设 \(dp[i][j]\) 为考虑到第 \(i\) 种花,考虑到第 \(j\) 个位置(不是一定摆在这个位置)的最大值。可以从 \(dp[i-1][j-1]\) 转移作为摆在上一种花后面,也可以从 \(dp[i][j-1]\) 转移作为之前的方案(\(j>i\) ,否则不可能有前面的方案),所以有转移方程:

\[dp[i][j] =\left \{ \begin{aligned} &\max (dp[i-1][j-1] + a[i],dp[i][j-1]) &,j>i\\ &dp[i-1][j-1] + a[i] &,j = i \end{aligned} \right. \]

注意这样的状态表达不用初始化负无穷,因为每种花必然会摆,不会出现因为负贡献就不摆的情况。

选择路径可以通过答案回溯,每次只需要用当前答案匹配 \(dp\) 内的值,最后一个与自己相同的就是摆放字典最小的。

时间复杂度 \(O(FV)\)

空间复杂度 \(O(FV)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int dp[107][107];

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int F, V;
    cin >> F >> V;
    for (int i = 1;i <= F;i++)
        for (int j = 1;j <= V;j++)
            cin >> dp[i][j];
    for (int i = 1;i <= F;i++) {
        for (int j = i;j <= V;j++) {
            if (i == j) dp[i][j] = dp[i - 1][j - 1] + dp[i][j];
            else dp[i][j] = max(dp[i][j - 1], dp[i - 1][j - 1] + dp[i][j]);
        }
    }
    vector<int> path;
    for (int i = F, j = V;i >= 1 && j >= 1;j--) {
        if (dp[i][j - 1] != dp[i][j]) {
            path.push_back(j);
            i--;
        }
    }
    cout << dp[F][V] << '\n';
    for (int i = path.size() - 1;i >= 0;i--) cout << path[i] << ' ';
    cout << '\n';
    return 0;
}
posted @ 2022-08-10 10:40  空白菌  阅读(49)  评论(0编辑  收藏  举报