9-2

#define _CRT_SECURE_NO_WARNINGS 

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
// 参考 http://blog.csdn.net/u014800748/article/details/43735015

// 题目中的条件是 n 种, 而例题嵌套矩形中的条件是 n 个
// n 种 block 不限供应,也可以将每种block以3种平面为底看成是不同的block,总共 3n 个 block,不限供应
// 如果 a[0] <= a[1] <= a[2], 每种 block 最多用到两个
// if a[0] <= a[1] <= a[2], at most 2 blocks of the same type will be used, the bottom with area a[0] * a[1], and the above with area a[1] * a[2]
struct block {
    int a[3]; // 3 dimensions
};

block blockTypes[30];
int n; // n <= 30
int maxiumHeight;
// n 种 block,每种 block 3 种底面,数组 d[30][3] 遍历各种情况
int d[30][3]; // d[idx][k] is the maxium height when block of type idx is at the bottom, and the height of block is dimension k
              // idx is the type number, at most 30 types
              // k represents the height of the block. each block has 3 dimentions, k may be 0, 1, or 2.

int kase = 0;
int max(int a, int b)
{
    if (a > b) return a;
    else return b;
}

/*
compute 2 other dimensions from dimension k
k            0    1    2
(k+1)%3        1    2    0
(k+2)%3        2    0    1

a[]是有序的,但这样计算不能保证另两个dimension有序,比如 k == 1 时
下面这种计算方式可以,如果用这种方式,dp(idx,k) 里面的 if(l < w) 和 if(ll < ww) 以及  (l > ww && w > ll) 都可以去掉
k                0    1    2
(2-k)/2            1    0    0
(3-k)/2 + 1        2    2    1

*/

// 这里的写法是 记忆化搜索
// 不太好用递归,如果用递归,需要有个计算次序,例题硬币问题里从最小的面值开始计算,例题9-1从最后一站向前计算, 这题里面没有明显的顺序
int dp(int idx, int k)
{
    if (d[idx][k] > 0) // already computed
        return d[idx][k];
    
    int l = blockTypes[idx].a[(k + 1) % 3]; // length
    int w = blockTypes[idx].a[(k + 2) % 3]; // width

    if (l < w){
        int tmp = l; l = w; w = tmp;
    }

    d[idx][k] = blockTypes[idx].a[k]; // initial value
    for (int i = 0; i < n; i++){
        for (int j = 0; j < 3; j++){

            int ll = blockTypes[i].a[(j + 1) % 3];
            int ww = blockTypes[i].a[(j + 2) % 3];
            
            if (ll < ww){
                int tmp = ll; ll = ww; ww = tmp;
            }

            if ((l > ll && w > ww) /*|| (l > ww && w > ll) */) { // 如果去掉上面的 if(l < w) 和 if(ll < ww) 这里的注释要恢复
                d[idx][k] = max(d[idx][k], dp(i,j) + blockTypes[idx].a[k]);
                maxiumHeight = max(maxiumHeight, d[idx][k]);
            }
        }
    }

    return d[idx][k];
}

int main()
{
    while (scanf("%d", &n) && n) {
        for (int i = 0; i < n; i++) {
            scanf("%d%d%d", &blockTypes[i].a[0], &blockTypes[i].a[1], &blockTypes[i].a[2]);
            sort(blockTypes[i].a, blockTypes[i].a + 3); // a[0] <= a[1] <= a[2]
        }

        maxiumHeight = 0;
        memset(d, 0, sizeof(d));

        for (int i = 0; i < n; i++){
            for (int k = 0; k < 3; k++){
                dp(i, k);
            }
        }

        printf("Case %d: maxium height = %d\n", ++kase, maxiumHeight);
    }

    return 0;
}

 

posted @ 2016-08-16 19:27  PatrickZhou  阅读(136)  评论(0编辑  收藏  举报