题目链接:http://judge.noi.cn/problem?id=1029
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX(a, b) a<b?b:a
#define M 102
#define N 4
int dp[M][M][M][N];
struct plane
{
int a, b, h;
} p[M][N];
//p[i][j]表示第i个立方体的第j个面,a,b分别为该面的长和宽,h为此时该立方体的高度
int main()
{
int m, n, k, r, i, j, l;
int a, b, c;
scanf("%d%d", &n, &m);
for(i = 1; i <= n; i++)
{
scanf("%d%d%d", &a, &b, &c);
if(a > b) swap(a, b); //将a,b,c排序
if(b > c) swap(b, c);
if(a > b) swap(a, b);
//排序后存储时,p[i][j].a的值始终小于p[i][j].b的值,这样可以使判断是否包含时更方便
p[i][1].a = a; p[i][1].b = b; p[i][1].h = c;
p[i][2].a = a; p[i][2].b = c; p[i][2].h = b;
p[i][3].a = b; p[i][3].b = c; p[i][3].h = a;
}
memset(dp, 0, sizeof(dp));
for(i = 1; i <= n; i++) //初始化,第1堆的第一个(可以不为第一个立方体,因为可以不选它),开始wrong在这里
for(j = 1; j < N; j++)
dp[i][1][i][j] = p[i][j].h;
for(k = 2; k <= n; k++){ //从第2个立方体开始循环
for(r = 1; r <= m && r < k; r++){ //遍历第r堆,r<k,因为k-1个立方体最多堆成k-1堆
for(i = 1; i < k; i++){ //遍历前k-1个立方体
for(j = 1; j < N; j++){ //遍历前k-1个立方体的每一个面
if(r < m) { //决策1:还没有m堆时,第k个立方体另立一堆
for(l = 1; l < N; l++)
dp[k][r+1][k][l] = MAX(dp[k][r+1][k][l], dp[k-1][r][i][j]+p[k][l].h);
}
for(l = 1; l < N; l++){ // 决策2:放在前一个上(条件是可以放下时)
if(p[k][l].a <= p[i][j].a && p[k][l].b <= p[i][j].b)
dp[k][r][k][l] = MAX(dp[k][r][k][l], dp[k-1][r][i][j]+p[k][l].h);
}
dp[k][r][i][j] = MAX(dp[k][r][i][j], dp[k-1][r][i][j]); //决策3:丢弃第k个
}
}
}
}
int ans = 0;
for(i = 1; i <= n; i++){
for(j = 1; j < N; j++)
{
if(ans < dp[n][m][i][j])
ans = dp[n][m][i][j];
}
}
printf("%d\n", ans);
return 0;
}