「线性DP」花店橱窗

花店橱窗

https://ac.nowcoder.com/acm/contest/24213/1005

题目描述

​ 小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 2^{31} 231,美观程度有正有负)

输出描述

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

样例

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

提示

  • 1 ≤ F ≤ V ≤ 100 1≤F≤V≤100 1FV100

解析

           花瓶
【1】  7 23 -5 -24 16
【2】  5 21 -4  10 23
【3】-21  5 -4 -20 20

根据题意可知,i 朵花和 i+1 朵花的关系是 i < i + 1 i < i+1 i<i+1 ,即上一朵花一定在下一朵花的左边,因此 j < j + 1 j < j+1 j<j+1 花瓶。

假设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示:第 i 朵花插在第 j 个瓶子上的美观度。

【1】  7 23 -5 -24 16
【2】  5 28 19  33 46
【3】-21 10 24   8 53

因为 j < j + 1 j < j + 1 j<j+1 ,所以 d p [ i ] [ j ] dp[i][j] dp[i][j] 等于 d p [ i − 1 ] [ 1 ] dp[i-1][1] dp[i1][1] d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1] dp[i1][j1] 这个闭区间之内的最大值加上 d p [ i ] [ j ] dp[i][j] dp[i][j] 的美观度。

怎么说呢,就是我插入了 d p [ i ] [ j ] dp[i][j] dp[i][j] 这个位置,那么我上一朵花的位置一定是在 d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1 ] dp[i1][j1] 的左边(包含),我们只需要选择这个区间内的最大值就行了。

  • dp[2][3] = 19:也就是上一朵花的美观度的最大值 ( d p [ 1 ] [ 2 ] = 23 dp[1][2] = 23 dp[1][2]=23) 加上当前插入的花瓶美观度( d p [ 2 ] [ 3 ] = − 4 dp[2][3] = -4 dp[2][3]=4)

我写题时遇到的坑:

  • 一直 45%,因为:初始化错了

    for(int i = 1; i <= F; i++) {
        for(int j = 1; j <= V; j++) {
            dp[i][j] = -INF;
        }
    }
    

    这样子,其实是没有初始化到第一列 d p [ 0 ] [ i ] dp[0][i] dp[0][i] ,结果就是其它的位置都是无穷小,而这一列无穷大,所以导致了 0 最大,所以最后的答案也是 0。

    3 5 
    7 23 -5 -24 16
    -20 -20 -20 -20 -20 
    -20 -20 -20 -20 -20 
    
    0
    0 0 0
    

    而正确答案是

    -17
    2 3 4
    
  • 初始值不够小,我一开始是:

    int INF = 0x3f; // 错误的
    

DP 信息:

  • 子问题:求 i 朵花插在第 j 个瓶子上的美观度。
  • DP 定义:第 i 朵花插在第 j 个瓶子上的美观度。
  • DP 方程: d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ k ] + w [ i ] [ j ] ) dp[i][j] = max(dp[i][j], dp[i-1][k] + w[i][j]) dp[i][j]=max(dp[i][j],dp[i1][k]+w[i][j])
  • DP 初始化: d p [ i ] [ j ] = − I N F dp[i][j] = -INF dp[i][j]=INF

代码

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int F = sc.nextInt(), V = sc.nextInt();
        int MAX = 105;
        int[][] w = new int[MAX][MAX];
        int[][] dp = new int[MAX][MAX];
        int[][] path = new int[MAX][MAX];
        int INF = 0xfffffff;
        
        for(int i = 1; i <= F; i++) Arrays.fill(dp[i], -INF);
        
        dp[0][0] = 0;
        
        for(int i = 1; i <= F; i++) {
            for(int j = 1; j <= V; j++) {
                w[i][j] = sc.nextInt();
            }
        }
        
        for(int i = 1; i <= F; i++) {
            for(int j = 1; j <= V; j++) {
                int pos = 0;
                // 寻找上一朵花的最大值
                for(int k = 1; k < j; k++) {
                    if(dp[i-1][k] > dp[i-1][pos]) pos = k;
                }
                dp[i][j] = dp[i-1][pos] + w[i][j];
                path[i][j] = pos; // 保存路径
            }
        }
        
        int k = 0;
        for(int i = F; i <= V; i++) {
            if(dp[F][i] > dp[F][k]) k = i;
        }
        System.out.println(dp[F][k]);
        path(F, k, path);
    }
    
    public static void path(int F, int k, int[][] path) {
        String str = k + "";
        for(int i = F; i > 1; i--) {
            str = path[i][k] + " " + str;
            k = path[i][k];
        }
        System.out.println(str);
        /*if(F == 0) return;
        path(F-1, path[F][k], path);
        System.out.print(k + " ");*/
    }
}

你可能感兴趣的:(#,动态规划,java,算法,动态规划,线性DP)