Uva 437 DAG上的dp

时间:2021-12-07 18:43:42

题意:

有n种长宽高为x,y,z的砖头,每种都有无数个。砖头可以用不同姿势的方向来盖。

砖头a以某种姿势可以盖在砖头b上,当且仅当a的底部的长宽都要比b的底部长宽要小。

问最高可以建多高?

思路:

其实就是白书DAG上dp一个基础题。归结为矩形嵌套问题,状态转移和三角形状态转移一样。

对于一个x,y,z砖头,它可以有3中姿势放置。注意矩形可以旋转90度,所以宽高位置没影响,主要在不同值上。

 (前两个为地面,后一个为高)

x, y, z

x, z, y

y, z, x

把每种姿势都记录下来,变成了有3*n种固定姿势的砖头。

然后建图, 注意双向图,mp[i][j] = true,表示砖头i可以盖在砖头j上,反之亦然,从外圈到内圈

 

#include <bits/stdc++.h>

using namespace std;
const int maxn = 100;
bool mp[maxn][maxn];
int d[maxn];
int n;

struct Node {
    int x,y,h;
    }node[maxn];

bool check(int i,int j) {
    return node[i].x<node[j].x && node[i].y<node[j].y ||
        node[i].x < node[j].y &&node[i].y < node[j].x;
    }

int dfs(int u) {
    if(d[u]!=-1) {
        return d[u];
    }
    //当前的自己的高度
    d[u] = node[u].h;
    for(int i = 0; i < n; i++) {
        if(mp[u][i]) {
            //d[u] = max(d[u],dfs(i)+node[u].h)
            //一开始这样写,循环每次循环d[u]就变了,所以加的不是这一层的高度,而是累加了
            //遍历当前u为起点的所有可到达的下一个"状态"
            d[u] = max(d[u],dfs(i)+node[u].h);

        }
    }
    return d[u];
}


int main()
{
//    freopen("in.txt","r",stdin);
    int casen;
    casen = 0;
    while(scanf("%d",&n)&&n) {
        for(int i = 0; i < n; i++) {
            scanf("%d%d%d",&node[i].x,&node[i].y,&node[i].h);
            node[n+i].x = node[i].y;
            node[n+i].y = node[i].h;
            node[n+i].h = node[i].x;
            node[n*2+i].x = node[i].x;
            node[n*2+i].y = node[i].h;
            node[n*2+i].h = node[i].y;
        }

        n *= 3;
        memset(mp,false,sizeof(0));
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                mp[i][j] = check(i,j);
            }
        }


        memset(d,-1,sizeof(d));
        int ans = 0;
        for(int i = 0; i < n; i++) {
            ans = max(ans,dfs(i));
        }

        printf("Case %d: maximum height = %d\n",++casen,ans);
    }
    return 0;
}