uva 437 巴比伦塔(DAG上dp)

巴比伦塔

紫书P269 看完紫书,终于可以自己写一个dp了 :)

【题目链接】巴比伦塔

【题目类型】DAG上dp

&题意:

有n种立方体 n<=30,每种有无穷个,要求选一些立方体摞成一根尽量高的柱子,上面的立方体长和宽必须严格小于下面的。

&题解:

看紫书前,我的想法:
这题就把所有的3种情况排个序啊,根据长和宽排,之后累计加高,就好了。

看紫书后,我的想法:
这是一个二元关系,而且没有环,又范围很小,所以用邻接矩阵建图,也就转化成DAG上的最长路径了。

差距:
之前的想法太幼稚,没有考虑到这样的情况:2 9 10之后是3 5 100 如果按照我之前的想法,那么我一定会用了长2 宽9 高10这个立方体,之后显然 高为100这个就用不到了,这明显不是最优的。
如果这块想通了,那么之后的想法也就没问题了:所以我们现在要做的是时时刻刻更新最大值,所以就是递归dp。

这题让我知道了,对于你并不知道这一步应该选择什么的时候,而且还没有规律,那么你也许就可以用dp,因为dp可以随时更新出你想要的东西。

【时间复杂度】O(n^2)

&代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
#define cle(a,val) memset(a,(val),sizeof(a))
#define SI(N) scanf("%d",&(N))
#define SII(N,M) scanf("%d %d",&(N),&(M))
#define SIII(N,M,K) scanf("%d %d %d",&(N),&(M),&(K))
#define rep(i,b) for(int i=0;i<(b);i++)
#define rez(i,a,b) for(int i=(a);i<=(b);i++)
#define red(i,a,b) for(int i=(a);i>=(b);i--)
const ll LINF = 0x3f3f3f3f3f3f3f3f;
#define PU(x) puts(#x);
#define PI(A) cout<<(A)<<endl;
#define DG(x) cout<<#x<<"="<<(x)<<endl;
#define DGG(x,y) cout<<#x<<"="<<(x)<<" "<<#y<<"="<<(y)<<endl;
#define DGGG(x,y,z) cout<<#x<<"="<<(x)<<" "<<#y<<"="<<(y)<<" "<<#z<<"="<<(z)<<endl;
#define PIar(a,n) rep(i,n)cout<<a[i]<<" ";cout<<endl;
#define PIarr(a,n,m) rep(aa,n){rep(bb, m)cout<<a[aa][bb]<<" ";cout<<endl;}
const double EPS = 1e-9 ;
/*     C o d i n g  S p a c e     */
const int MAXN = 100 + 5 ;
int t1, t2, t3, n, cnt, K;
struct node {
    int x, y, z;
    bool operator <(const node& A) const {
        return x == A.x ? y < A.y : x < A.x;
    }
} s[MAXN], te;
bool G[MAXN][MAXN];
set<node> sen;
void input() {
    te.x = t1, te.y = t2, te.z = t3;
    if (te.x > te.y) swap(te.x, te.y);
    sen.insert(te);
    te.x = t1, te.y = t3, te.z = t2;
    if (te.x > te.y) swap(te.x, te.y);
    sen.insert(te);
    te.x = t2, te.y = t3, te.z = t1;
    if (te.x > te.y) swap(te.x, te.y);
    sen.insert(te);
}
void buildG() {
    rep(i, cnt) {
        rep(j, cnt) {
            if (s[i].x < s[j].x && s[i].y < s[j].y) {
                G[i][j] = 1;
            }
        }
    }
}
ll d[MAXN];
ll dp(int i) {
    ll& ans = d[i];
    if (ans >= 0) return ans;
      //刚开始时他的高就只有他自己的高
    ans = s[i].z;
    rep(j, cnt) {
        if (G[i][j]) {
                    //注意这里:是dp(j) + s[i].z 不是dp(j) + s[j].z
            ans = max(ans, dp(j) + s[i].z);
        }
    }
    return ans;
}
void Solve() {
    while (~SI(n), n) {
        cle(G, 0);
        sen.clear();
        rep(i, n) {
            SIII(t1, t2, t3);
            input();
        }
        cnt = 0;
        for (auto i = sen.begin(); i != sen.end(); i++, cnt++) {
            s[cnt].x = (*i).x, s[cnt].y = (*i).y, s[cnt].z = (*i).z;
        }
        buildG();
//      rep(i,cnt){
//          DGGG(s[i].x,s[i].y,s[i].z);
//      }
//      PIarr(G,10,10)
        ll ans = 0;
        rep(i, cnt) {
            cle(d, -1);
            ll te = dp(i);
            ans = max(te, ans);
        }
        printf("Case %d: maximum height = %lld\n", ++K, ans);
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("C:\\Users\\Zmy\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\Zmy\\Desktop\\out.txt","w",stdout);
#endif
//iostream::sync_with_stdio(false);
//cin.tie(0), cout.tie(0);
//  int T;cin>>T;while(T--)
    Solve();
    return 0;
}

转载于:https://www.cnblogs.com/s1124yy/p/5947440.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值