题意,给出 n 种长方体的 a, b, c,每种都有无限多个,把它们盖成一个塔,要求相邻的下层长和宽都要严格大于上层。
刚开始想了个DAG上动态规划的做法(感觉直观上第一反应就是这种做法啊。。。)但是貌似有点小问题,虽然样例能过,但是会 STACK_OVERFLOW ,然后以为是记忆化搜索的问题,改成非递归的,直接 TLE 了。。。
于是上网找了正解。。。
显然每个长方体都有三种不同的形态,因为题目要求严格小于,所以每种长方体最多用三次。
把每种长方体的6种状态都枚举(长宽互换算两种,便于后面的排序),将其按先 x 后 y 排序(先 y 后 x 其实也一样。)
显然最优序列是排序后序列的一个子序列,而且是最长上升子序列。
此处上升的定义是 x 和 y 都要严格大于。
方程:dp[i] = h[i] + max(dp[j]) , j < i 且 i 可以放在 j 上。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 35 * 6;
int n, vcnt;
typedef struct Blk {
int x, y, h;
}Blk;
Blk blk[maxn];
int dp[maxn];
void init()
{
vcnt = 0;
memset(dp, -1, sizeof(dp));
}
bool cmp(Blk a, Blk b)
{
if(a.x == b.x) return a.y > b.y;
else return a.x > b.x;
}
void addv(int a, int b, int c)
{
blk[vcnt].x = a;
blk[vcnt].y = b;
blk[vcnt].h = c;
vcnt++;
}
bool check(int i, int j)
{
return (blk[i].x > blk[j].x && blk[i].y > blk[j].y);
}
int main()
{
int ca = 1;
while(scanf("%d", &n) && n) {
int a, b, c;
init();
for(int i = 0; i < n; i++) {
scanf("%d%d%d", &a, &b, &c);
addv(a, b, c);
addv(b, a, c);
addv(a, c, b);
addv(c, a, b);
addv(b, c, a);
addv(c, b, a);
}
sort(blk, blk + vcnt, cmp);
for(int i = 0; i < vcnt; i++) {
dp[i] = 0;
for(int j = 0; j < i; j++) {
if(check(j, i))
dp[i] = max(dp[j], dp[i]);
}
dp[i] += blk[i].h;
}
int ans = 0;
for(int i = 0; i < vcnt; i++)
ans = max(ans, dp[i]);
printf("Case %d: maximum height = %d\n", ca++, ans);
}
return 0;
}
顺便附一下 TLE 的 DAG 动态规划代码。。。。。。。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 110 * 3;
int mat[maxn][maxn];
int x[maxn], y[maxn], h[maxn];
int outd[maxn];
bool done[maxn];
int n, vcnt;
void init()
{
memset(mat, -1, sizeof(mat));
memset(outd, 0, sizeof(outd));
memset(done, false, sizeof(done));
vcnt = 0;
}
void adde(int a, int b)
{
mat[a][b] = h[b];
outd[a]++;
}
void addv(int a, int b, int c)
{
x[vcnt] = a;
y[vcnt] = b;
h[vcnt] = c;
for(int i = 0; i < vcnt; i++) {
int s1 = x[i] - a, s2 = y[i] - b;
int s3 = x[i] - b, s4 = y[i] - a;
if(s1 * s2 > 0 || s3 * s4 > 0) {
if(s1 > 0 || s3 > 0)
adde(i, vcnt);
else if(s1 < 0 || s3 < 0)
adde(vcnt, i);
}
}
vcnt++;
}
//int dpa[maxn];
//
//int dp(int cur)
//{
// if(dpa[cur] != -1) return dpa[cur];
// int ret = 0;
// for(int i = first[cur]; i != -1; i = next[i])
// ret = max(ret, wt[i] + dp(to[i]));
// return dpa[cur] = ret;
//}
int dp[maxn];
int main()
{
int ca = 1;
while(~scanf("%d", &n) && n) {
init();
for(int i = 0; i < n; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
addv(a, b, c);
addv(a, c, b);
addv(b, c, a);
}
int ans = 0, cnt = 0;
// memset(dpa, -1 ,sizeof(dpa));
while(cnt < vcnt) {
for(int i = 0; i < vcnt; i++) {
if(outd[i] == 0 && !done[i]) {
dp[i] = 0;
for(int j = 0; j < vcnt; j++) {
if(mat[i][j] > 0)
dp[i] = max(dp[i], mat[i][j] + dp[j]);
}
for(int j = 0; j < vcnt; j++) {
if(mat[j][i] > 0)
outd[j]--;
}
done[i] = 1;
cnt++;
}
}
}
for(int i = 0; i < vcnt; i++)
ans = max(ans, h[i] + dp[i]);
printf("Case %d: maximum height = %d\n", ca++, ans);
}
return 0;
}
STACK_OVERFLOW 的递归版本。。。。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 110 * 3, maxe = 130000;
int x[maxn], y[maxn], h[maxn];
int fr[maxe], to[maxe], wt[maxe];
int first[maxn], next[maxe];
int n, ecnt, vcnt;
void init()
{
memset(first, -1, sizeof(first));
memset(next, -1, sizeof(next));
ecnt = vcnt = 0;
}
void adde(int a, int b)
{
fr[ecnt] = a;
to[ecnt] = b;
wt[ecnt] = h[b];
next[ecnt] = first[a];
first[a] = ecnt;
ecnt++;
}
void addv(int a, int b, int c)
{
x[vcnt] = a;
y[vcnt] = b;
h[vcnt] = c;
for(int i = 0; i < vcnt; i++) {
int s1 = x[i] - a, s2 = y[i] - b;
int s3 = x[i] - b, s4 = y[i] - a;
if(s1 * s2 > 0 || s3 * s4 > 0) {
if(s1 > 0 || s3 > 0)
adde(i, vcnt);
else if(s1 < 0 || s3 < 0)
adde(vcnt, i);
}
}
vcnt++;
}
int dpa[maxn];
int dp(int cur)
{
if(dpa[cur] != -1) return dpa[cur];
int ret = 0;
for(int i = first[cur]; i != -1; i = next[i])
ret = max(ret, wt[i] + dp(to[i]));
return dpa[cur] = ret;
}
int main()
{
int ca = 1;
while(~scanf("%d", &n) && n) {
init();
for(int i = 0; i < n; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
addv(a, b, c);
addv(a, c, b);
addv(b, c, a);
}
int ans = 0;
memset(dpa, -1 ,sizeof(dpa));
for(int i = 0; i < vcnt; i++)
ans = max(ans, h[i] + dp(i));
printf("Case %d: maximum height = %d\n", ca, ans);
}
return 0;
}