[黑书 - 动态规划] 例题5 - 积木游戏

ECNUOJ1244 - 积木游戏

M = Dp ( i, a, b, k ) 表示当前已用到第 a 个积木, 得到了 i 根柱子, 顶部的积木是第 b 个且 k 面朝上, M 为从Dp ( i, a, b, k ) 到决策结束能获得的最大高度。理解了这个DP方程才能正确的写出状态转移方程

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define INF (int)(1e9)
#define MAXN 8
using namespace std;
struct P {
    int a, b, c;
};
P kuai[110];
int dp[110][110][110][4], n, m;
int get_height(P a, int k) {
    if (k == 0) return a.c;
    if (k == 1) return a.a;
    if (k == 2) return a.b;
}
//把b放在a上
int is_ok(P a, P b, int k1, int k2) {
    int a1, b1, a2, b2;
    if (k1 == 0) a1 = a.a, b1 = a.b;
    if (k1 == 1) a1 = a.b, b1 = a.c;
    if (k1 == 2) a1 = a.a, b1 = a.c;
    if (k2 == 0) a2 = b.a, b2 = b.b;
    if (k2 == 1) a2 = b.b, b2 = b.c;
    if (k2 == 2) a2 = b.a, b2 = b.c;
    if ((a1 >= a2 && b1 >= b2) || (a1 >= b2 && b1 >= a2)) return true;
    return false;
}
int solve(int i, int a, int b, int k) {
    if (dp[i][a][b][k] != -1) return dp[i][a][b][k];
    if (i == m+1 || b == n+1 || a == n+1) return dp[i][a][b][k] = 0;
    int res = 0;
    //另起一堆
    if (i < m) for (int _ = 0; _ < 3; ++ _) {
        res = max(res, solve(i+1,a+1,a+1,_)+get_height(kuai[a+1], _));
    }
    //接着放
    if (i) for (int _ = 0; _ < 3; ++ _) {
        if (a < n && is_ok(kuai[b],kuai[a+1],k,_)) {
            res = max(res, solve(i,a+1,a+1,_)+get_height(kuai[a+1], _));
        }
    }
    //扔了
    res = max(res, solve(i,a+1,b,k));
    return dp[i][a][b][k] = res;
}
int main() {
    #ifdef LOCAL
        freopen("data1.in", "r", stdin);
    #endif // LOCAL
    kuai[0].a = kuai[0].b = kuai[0].c = INF;
    while (cin >> n >> m) {
        memset(dp, -1, sizeof(dp));
        for (int i = 1; i <= n; ++ i) cin >> kuai[i].a >> kuai[i].b >> kuai[i].c;
        int res = solve(0,0,0,0);
        cout << res << endl;
    }
}

测试数据

data.in

4 2
10 5 5
8 7 7
2 2 2
6 6 6
4 2
1 1 1
2 2 2
3 3 3
5 5 5
4 1
1 1 1
2 2 2
3 3 3
5 5 5
4 3
1 1 1 
2 2 2
3 3 3
5 5 5
4 4
1 1 1
2 2 2
3 3 3
5 5 5
4 2
100 5 5
3 3 100
2 100 2
1 1 100
6 1
3 3 3
2 2 2
900 900 900
2 2 2
900 900 900
1 1 1

data.out

24
8
5
10
11
400
1801


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值