紫书上动态规划第二道例题。
这道题其实就是求DAG最长路,而且是无固定源点和终点的,基本上套用紫书上那种格式就行。
这道题难在如何表示。
这道题其实就是一个(len,wide,high)立方体可以拆成三个来看,所以直接造三种状态出来就好了,一个高为high,一个高为len,一个高为wide。
由于是要求下一个的长和宽必须严格小于当前的长和宽,我们先把这些都排序存起来,小的和小的比较,大的和大的比较可以剩下很多麻烦。
剩下的就是改一改DAG求最长路的代码,d【i】【j】表示第i个立方体的第j个状态可以造出的最大高度。
代码如下:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<utility>
#include<stack>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<map>
using namespace std;
const int maxn = 35;
int n;
int d[maxn][5], G[maxn][5][5], a[5];
int length[maxn], wideth[maxn], high[maxn];
int dp(int x, int y) {
int& ans = d[x][y];
int l = G[x][y][0], w = G[x][y][1];
if(ans)
return ans;
ans = G[x][y][2];
for(int i = 1; i <= n; i++) {
for(int j = 0; j < 3; j++) {
int l2 = G[i][j][0], w2 = G[i][j][1];
if(l > l2 && w > w2) {
ans = max(G[x][y][2] + dp(i, j), ans);
}
}
}
return ans;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
int Case = 1;
while(scanf("%d", &n) != EOF) {
memset(d, 0, sizeof(d));
if(n == 0)
break;
for(int i = 1; i <= n; i++) {
scanf("%d%d%d", &a[0], &a[1], &a[2]);
sort(a, a + 3);
G[i][0][0] = a[0], G[i][0][1] = a[1], G[i][0][2] = a[2];
G[i][1][0] = a[1], G[i][1][1] = a[2], G[i][1][2] = a[0];
G[i][2][0] = a[0], G[i][2][1] = a[2], G[i][2][2] = a[1];
}
for(int i = 1; i <= n; i++) {
for(int j = 0; j < 3; j++) {
dp(i, j);
}
}
int Max = 0;
for(int i = 1; i <= n; i++) {
for(int j = 0; j < 3; j++) {
if(Max < d[i][j])
Max = d[i][j];
}
}
printf("Case %d: maximum height = %d\n", Case++, Max);
}
return 0;
}