题目
巴比伦人有n种长方形方块,每种有无限个,第i种方块的三边边长是xi,yi,zi。对于每一个方块,你可以任意选择一面作为底,这样高就随着确定了。举个例子,同一种方块,可能其中一个是竖着放的,一个是侧着放的,一个是横着放的。
他们想要用堆方块的方式建尽可能高的塔。问题是,只有一个方块的底的两条边严格小于另一个方块的底的两条边,这个方块才能堆在另一个上面。这意味着,一个方块甚至不能堆在一个底的尺寸与它一样的方块的上面。
解题思路
- 对于每种长方体,总共有三种摆放方式
- 尺寸相同且摆放方式相同的长方体最多使用一次。
解法一:DP
状态转移方程: d p [ i ] = d p [ j ] + a [ i ] . h dp[i]=dp[j]+a[i].h dp[i]=dp[j]+a[i].h
AC代码:
#include <bits/stdc++.h>
using namespace std;
int n, CA;
struct node
{
int x, y, z;
bool operator<(const node &temp) const
//重载运算符,保证只有i后面的长方体可能放在i上。
{
if (x == temp.x)
return y > temp.y;
return x > temp.x;
}
} a[95];
int ct;
int ans;
int dp[95];
void add(int x, int y, int z)
{
a[++ct].x = x;
a[ct].y = y;
a[ct].z = z;
}
void solve()
{
for (int i = 1; i <= n; i++)
{
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
add(min(x, y), max(x, y), z);
add(min(x, z), max(x, z), y);
add(min(y, z), max(y, z), x);
}
sort(a + 1, a + 1 + ct);
for (int i = 1; i <= ct; i++)
{
dp[i] = a[i].z;
for (int j = 1; j < i; j++)
if (a[j].x > a[i].x && a[j].y > a[i].y)
dp[i] = max(dp[i], dp[j] + a[i].z);
ans = max(dp[i], ans);
}
printf("Case %d: maximum height = %d\n", ++CA, ans);
}
int main()
{
while (cin >> n && n)
{
ct = ans = 0;
solve();
}
return 0;
}
解法二:建图最长路
最长路可以用SPFA求,时间复杂度为 O ( V E ) O(VE) O(VE),也可以用拓扑排序+DP求时间复杂度为 O ( N ) O(N) O(N)
SPFA代码:
#include <bits/stdc++.h>
using namespace std;
int n, CA;
struct node
{
int x, y, z;
bool operator>(const node &temp) const
{
return (x > temp.x && y > temp.y);
}
} a[95];
int ct, ans;
void add(int x, int y, int z)
{
a[++ct].x = x;
a[ct].y = y;
a[ct].z = z;
}
struct node2
{
int v, next, w;
} Edge[8110];//最多90*90条边(虽然实际上远达不到
int head[95], cnt;
void addedge(int u, int v, int w)
{
Edge[cnt].v = v;
Edge[cnt].w = w;
Edge[cnt].next = head[u];
head[u] = cnt++;
}
bool vis[95];
int dis[95];
queue<int> q;
int spfa(int beg)
{
dis[beg] = a[beg].z;
q.push(beg);
while (q.size())
{
int pos = q.front();
q.pop();
vis[pos] = 0;
for (int i = head[pos]; i; i = Edge[i].next)
{
int v = Edge[i].v;
int w = Edge[i].w;
if (dis[v] < dis[pos] + w)
{
dis[v] = dis[pos] + w;
if (!vis[v])
q.push(v), vis[v] = 1;
}
}
}
int res = 0;
for (int i = 1; i <= ct; i++)
res = max(res, dis[i]);
return res;
}
void solve()
{
for (int i = 1; i <= n; i++)
{
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
add(min(x, y), max(x, y), z);
add(min(x, z), max(x, z), y);
add(min(y, z), max(y, z), x);
}
for (int i = 1; i <= ct; i++)
for (int j = 1; j <= ct; j++)
if (a[i] > a[j])
addedge(i, j, a[j].z);
for (int i = 1; i <= ct; i++)
{
memset(vis, 0, sizeof vis);
memset(dis, 0, sizeof dis);
ans = max(ans, spfa(i));
}
printf("Case %d: maximum height = %d\n", ++CA, ans);
}
int main()
{
while (cin >> n && n)
{
ct = ans = 0;
cnt = 1;
memset(head, 0, sizeof head);
solve();
}
return 0;
}
拓扑排序+DP代码:
#include <bits/stdc++.h>
using namespace std;
int n, CA;
struct node
{
int x, y, z;
bool operator>(const node &temp) const
{
return (x > temp.x && y > temp.y);
}
} a[95];
int ct, ans;
void add(int x, int y, int z)
{
a[++ct].x = x;
a[ct].y = y;
a[ct].z = z;
}
struct node2
{
int v, next, w;
} Edge[8110]; //最多90*90条边(虽然实际上远达不到
int head[95], cnt;
void addedge(int u, int v, int w)
{
Edge[cnt].v = v;
Edge[cnt].w = w;
Edge[cnt].next = head[u];
head[u] = cnt++;
}
int degree[95], dp[95], vis[95];
int topological()
{
memset(vis, 0, sizeof vis);
int cot = 0;
while (1)
{
int pos = 0;
for (int i = 1; i <= ct; i++)
{
if (!degree[i] && !vis[i])
{
pos = i;
break;
}
}
vis[pos] = 1;
for (int i = head[pos]; i; i = Edge[i].next)
{
degree[Edge[i].v]--;
dp[Edge[i].v] = max(dp[pos] + Edge[i].w, dp[Edge[i].v]);
ans = max(ans, dp[Edge[i].v]);
}
cot++;
if (cot == ct)
break;
}
return ans;
}
void solve()
{
for (int i = 1; i <= n; i++)
{
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
add(min(x, y), max(x, y), z);
add(min(x, z), max(x, z), y);
add(min(y, z), max(y, z), x);
}
for (int i = 1; i <= ct; i++)
for (int j = 1; j <= ct; j++)
if (a[i] > a[j])
{
addedge(i, j, a[j].z);
degree[j]++;
}
for (int i = 1; i <= ct; i++)
dp[i] = a[i].z;
printf("Case %d: maximum height = %d\n", ++CA, topological());
}
int main()
{
while (cin >> n && n)
{
ct = ans = 0;
cnt = 1;
memset(head, 0, sizeof head);
solve();
}
return 0;
}