紫书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;
}