动态规划 种树

UPC2019秋个人训练赛1-B种树

题目描述

事实上,小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一定为偶数。

 

AC代码:

四维数组 f[i][j][k][l],表示第 i 个位置种树 j,它的前一棵树是 k,第一棵树是 l。

状态转移:

  1. 第i个位置种树1时,前一棵树是2,前前一棵树是1  or  前一棵树是3,前前一棵树是1或2

     

  2. 第i个位置种树2时,前一棵树是1,前前一棵树是2或3  or  前一棵树是3,前前一棵树是1或2

  3. 第i个位置种树3时,前一棵树是1,前前一棵树是2或3  or  前一棵树是2,前前一棵树是3

     

(注:1、2、3分别表示树高为10、20、30的树)

#include
 
using namespace std;
const int N = 100002;
int a[N][4], f[N][4][4][4];//f[i][j][k][l]表示第i个位置种树j,他的前一棵树是k,第一棵树是l。10、20、30分别用1、2、3表示
int n, ans;
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
 
    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= 3; ++j) {
            cin >> a[i][j];
        }
    }
    /*初始化位置1*/
    f[1][1][2][1] = f[1][1][3][1] = a[1][1];
    f[1][2][1][2] = f[1][2][3][2] = a[1][2];
    f[1][3][1][3] = f[1][3][2][3] = a[1][3];
    for (int i = 2; i <= n; ++i) {
        for (int j = 1; j <= 3; ++j) { //j:1~3 表示第一个位置种树j
            //第i个位置种树1时,前一棵树是2,前前一棵树是1 /\ or 前一棵树是3,前前一棵树是1或2
            f[i][1][2][j] = a[i][1] + f[i - 1][2][1][j];
            f[i][1][3][j] = a[i][1] + max(f[i - 1][3][1][j], f[i - 1][3][2][j]);
            //第i个位置种树2时,前一棵树是1,前前一棵树是2或3 or 前一棵树是3,前前一棵树是1或2
            f[i][2][1][j] = a[i][2] + max(f[i - 1][1][2][j], f[i - 1][1][3][j]);
            f[i][2][3][j] = a[i][2] + max(f[i - 1][3][1][j], f[i - 1][3][2][j]);
            //第i个位置种树3时,前一棵树是1,前前一棵树是2或3 or 前一棵树是2,前前一棵树是3
            f[i][3][1][j] = a[i][3] + max(f[i - 1][1][2][j], f[i - 1][1][3][j]);
            f[i][3][2][j] = a[i][3] + f[i - 1][2][3][j];
        }
    }
    /*选最大值*/
    ans = max(f[n][1][2][2], f[n][1][2][3]);
    ans = max(ans, f[n][1][3][2]);
    ans = max(ans, f[n][1][3][3]);
    ans = max(ans, f[n][2][1][1]);
    ans = max(ans, f[n][2][3][3]);
    ans = max(ans, f[n][3][1][1]);
    ans = max(ans, f[n][3][1][2]);
    ans = max(ans, f[n][3][2][1]);
    ans = max(ans, f[n][3][2][2]);
 
    cout << ans << endl;
    return 0;
}
/**************************************************************
    Problem: 13439
    User: Ytu201820
    Language: C++
    Result: 正确
    Time:42 ms
    Memory:28740 kb
****************************************************************/

三维数组

f[i][j][k] 表示第i个位置种树 j,大小情况为k(k=0:前一个位置比当前位置小,k=1:前一个位置比当前位置大,即 0: / , 1: \)

#include
 
using namespace std;
const int N = 100002;
int a[N][3], f[N][3][2];
int n;
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < 3; ++j) {
            cin >> a[i][j];
        }
    }
    for (int j = 0; j < 3; ++j) a[n + 1][j] = a[1][j];
 
    /* 0: / , 1: \ */
    for (int i = 2; i <= n + 1; ++i) {
        f[i][0][1] = a[i][0] + max(f[i - 1][1][0], f[i - 1][2][0]);
        f[i][2][0] = a[i][2] + max(f[i - 1][0][1], f[i - 1][1][1]);
        f[i][1][0] = a[i][1] + f[i - 1][0][1];
        f[i][1][1] = a[i][1] + f[i - 1][2][0];
    }
    int ans = 0;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 2; j++)
            ans = max(ans, f[n + 1][i][j]);
 
    cout << ans << endl;
    return 0;
}
/**************************************************************
    Problem: 13439
    User: Ytu201820
    Language: C++
    Result: 正确
    Time:28 ms
    Memory:5696 kb
****************************************************************/

 

你可能感兴趣的:(动态规划)