【2019 暑假JSOI Day 1 T2】 种树(dp)

5 篇文章 0 订阅

题目

【题目背景】
事实上, 小 X 邀请两位奆老来的目的远不止是玩斗地主, 主要是为了抓来苦力, 替他的
后花园种树……
【题目描述】
小 X 的后花园是环形的, 他想在花园周围均匀地种上 n 棵树, 但是奆老花园的土壤当然
非同寻常, 每个位置适合种的树都不一样, 一些树可能会因为不适合这个位置的土壤而损失
观赏价值。
小 X 最喜欢 3 种树, 这 3 种树的高度分别为 10,20,30。 小 X 希望这一圈树种得有层次感,
所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低, 并且在此条件下, 小 X
想要你设计出一套方案, 使得观赏价值之和最高。
【输入格式】
第一行为一个正整数 n, 表示需要种的树的棵树。
接下来 n 行, 每行 3 个不超过 10000 的正整数 ai,bi,ci, 按顺时针顺序表示了第 i 个位置
种高度为 10,20,30 的树能获得的观赏价值。
注意: 第 i 个位置的树与第 i+1 个位置的树相邻, 特别地, 第 1 个位置的树与第 n 个位
置的树相邻。
【输出格式】
一行一个正整数, 为最大的观赏价值和。
【输入样例】
4 1
3 2
3 1 2
3 1 2
3 1 2
【输出样例】
11
【样例解释】
第 1 至 n 个位置分别种上高度为 20,10,30,10 的树, 价值最高。
【数据范围】
对于 20%的数据, 有 n≤10
对于 40%的数据, 有 n≤100
对于 60%的数据, 有 n≤1000
对于 100%的数据, 有 4≤n≤100000 并保证 n 一定为偶数。

思路

交错文件,当场死亡。。。
20分很好拿吧。
枚举 N 个位置的 10,20,30 三种情况, 时间复杂度 O(3^n) 。
然后我们发现不用每次都枚举 3 个状态, 除了上次的状态还有 2 个状态, 时间复杂度 O(2^n),这样能多用自己的实力拿( )分。

正解 dp(我 dp 重测80分 发现状态少了一维)
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 表示第 i i i 个位置高度为 j j j 的最大观赏值, k = 1 k=1 k=1 则表示第 j j j 位比第 j − 1 j-1 j1 位大, k = 2 k=2 k=2 则表示第 j j j 位比第 j − 1 j-1 j1 位小。
但是还要注意这是环形。
加一维, 表示第一次选的高度为 10 / 20 / 30 10/20/30 10/20/30
最后结果就是就是六个状态中的最大值。

m a x { d p [ n ] [ 1 ] [ 2 ] [ 2 ] d p [ n ] [ 1 ] [ 2 ] [ 3 ] d p [ n ] [ 2 ] [ 1 ] [ 1 ] d p [ n ] [ 2 ] [ 2 ] [ 3 ] d p [ n ] [ 3 ] [ 1 ] [ 1 ] d p [ n ] [ 3 ] [ 1 ] [ 2 ] max\left\{\begin{matrix}dp[n][1][2][2] \\ dp[n][1][2][3] \\ dp[n][2][1][1] \\ dp[n][2][2][3] \\ dp[n][3][1][1] \\ dp[n][3][1][2] \end{matrix}\right. maxdp[n][1][2][2]dp[n][1][2][3]dp[n][2][1][1]dp[n][2][2][3]dp[n][3][1][1]dp[n][3][1][2]

代码

#include <bits/stdc++.h>
using namespace std;
const int M = 100100;
int a[M], b[M], c[M], dp[M][4][4][4];
int n, m, ans;
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d%d%d", &a[i], &b[i], &c[i]);
    dp[1][1][2][1] = a[1];
    dp[1][2][1][2] = dp[1][2][2][2] = b[1];
    dp[1][3][1][3] = c[1];
    for (int i = 2; i <= n; i++) {
        for (int j = 1; j <= 3; j++) {
            dp[i][1][2][j] = max(dp[i-1][2][1][j], dp[i-1][3][1][j])+a[i];
            dp[i][2][1][j] = b[i]+dp[i-1][1][2][j];
            dp[i][2][2][j] = b[i]+dp[i-1][3][1][j];
            dp[i][3][1][j] = c[i]+max(dp[i-1][1][2][j], dp[i-1][2][2][j]);
        }
    }
    printf("%d", max(ans, max(dp[n][1][2][2], max(dp[n][1][2][3], max(dp[n][2][1][1], max(dp[n][2][2][3], max(dp[n][3][1][1], dp[n][3][1][2])))))));
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值