SDNU 1044 花瓶插花(DP)

花瓶插花题目链接

1044.花瓶插花

Time Limit: 1000 MS    Memory Limit: 32768 KB
Total Submission(s): 270    Accepted Submission(s): 30

Description

有m朵花和n个花瓶,要把这些花全部插入某些花瓶中,花瓶和花都是有序的,花在花瓶中的先后顺序必须与给定顺序相同,每朵花插入每个花瓶能得到的美观程度都不一定相同,选择一些和花瓶,求插花能得到的最大美观程度。

Input

第一行是两个整数m, n(1 <= m <= n <= 1000),表示花的数量和花瓶的数量。之后m行,每行n个正整数(<= 100),这m行中第i行的第j个数字表示第i朵花插入第j个花瓶的美观程度。

Output

一个整数,最大的总美观程度。

Sample Input

3 5
5 9 3 2 4
1 3 2 9 5
4 2 1 3 5

Sample Output

23

Source

Unknown

这道题一看就想到用dfs,一点一点往下搜,但是速度实在是太慢了,因为这个棋盘高达1000 * 1000,一个点一个点搜索必然超时,所以就想到动态保存一下, 也就是动态规划

状态转移方程(设矩阵为m 行 n 列):

dp[i][j] = max(dp[i-1][j-1] + val[i][j], dp[i][j-1])   (j >= i)

dp[i][j] = 0                                                       (j <   i)

为什么是这个转移方程呢,坑死我了。。。第一个容易理解

例如: 题目给的例子:

3 5

5 9 3 2 4

1 3 2 9 5

4 2 1 3 5

使用状态转移方程更新后dp数组为

5 9 9 9 9

0 8 11 18 18

0 0 9 14 23

(应该能看明白,原理就是更新可以更新的部分,将无用的部分更新成左边的最大值,便于下一行更新时利用)

至于第二个部分dp[i][j] = 0 (j < i)是真的坑人,让我wa了五六次,都绝望了。仔细想一想还是自己太菜了考虑不周全,如果j > i,    a[i][j]是不能当作花瓶放花的(想一想为什么)因为在之前已经放了 i-1枝花,放的最紧凑的情况也得是i == j时才能放得下第i枝花, 所以需要保证 i >= j, 如何实现代码里会提到,很简单,但是如果不注意这一点会出大问题(例如,把题目给的样例输入的左下角数据改成100000 看看会出什么乱子)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int a[1005][1005];
int dp[1005][1005];
int main()
{
    int m, n;
    scanf("%d%d",&m,&n);
    for(int i = 1; i <= m; i ++)
        for(int j = 1; j <= n; j ++)
        scanf("%d",&a[i][j]);
    memset(dp, 0, sizeof(dp));
    for(int i = 1; i <= m; i ++)
        for(int j = i; j <= n; j ++){ //坑点,j不从1开始遍历,而是j = i时
            dp[i][j] = max(dp[i - 1][j - 1] + a[i][j], dp[i][j - 1]);
        }
    printf("%d\n",dp[m][n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41444888/article/details/81209103
今日推荐