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