花店橱窗(线性DP、递归记录路径)

题目:

小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 ≤ F ≤ V ≤ 100,

输入样例:
3 5
7 23 -5 -24 16
5 21 -4 10 23
-21 5 -4 -20 20

输出样例:
53
2 4 5

  • 题解:利用线性dp的思想求出状态转移方程,并用递归的思想记录下花存放的位置.
  • 集合表示:f[i][j]表示第i朵花放在第j个花瓶时前(i-1)朵花满足最大美观程度,pos[i][j]表示第i朵花放在第j个花瓶时,第(i-1)朵花所放的位置(此时需满足最大美观程度)
  • 状态转移方程:
    1. f[i][j]需要初始化为-0x3f,因为美观度存在负值,而f[1][j]需初始化为a[1][j],因为第一束花放入第j个花瓶不会受到前面花插入的影响
    2. 选择第i朵花(i >1)插入第j个花瓶时,需要选择第(i-1)朵花所插入的位置(k:1 -> (j-1)),并找出f[i][j]最大值后记录下第(i-1)朵花在第i朵花插入到第j个花瓶时的位置pos[i][j]
    3. 需要用ans数组记录需要输出花束插入花瓶的位置
    4. 核心方程:f[i][j] = max(f[i][j] , f[i-1][k] + a[i][j])
      -代码:
#include<iostream>
#include<cstring>
using namespace std;
const int N = 105;
const int inf = 0x3f3f3f3f;
int f[N][N]; //f(i, j):第i种花摆放在第j个位置时,前i-1种花摆放为最大美观程度
int pos[N][N], a[N][N], ans[N];
int n, m;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n >> m;
    memset(f, -0x3f, sizeof f);
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
            if(i == 1) f[i][j] = a[i][j];
        }
    }
    for(int i = 2; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            for(int k = 1; k <= j - 1; k++)
            {
                if(f[i][j] < f[i-1][k] + a[i][j])
                {
                    f[i][j] = f[i-1][k] + a[i][j];
                    pos[i][j] = k; //当第i束花放在第j个花瓶时,存第(i-1)束花放入的位置
                }
            }
        }
    }
    int res = -inf, lastP = -1;
    for(int i = 1; i <= m; i++)
    {
        if(res < f[n][i])
        {
             res = f[n][i];
             lastP = i; //最后一束花存放的位置
        }
    }
    cout << res << endl;
    for(int i = n; i >= 1; i--)
    {
        ans[i] = lastP;
        lastP = pos[i][lastP];
    }
    for(int i = 1; i <= n; i++)
        cout << ans[i] << " ";
    return 0;
}

posted @ 2021-02-26 17:06  ~K2MnO4  阅读(198)  评论(0)    收藏  举报