题意:有n(n≤30)种立方体,每种有无穷多个。要求选一些立方体摞成一根尽量高的柱子(可以自行选择哪一条边作为高),使得每个立方体的底面长宽分别严格小于它下方立方体的底面长宽。
样例输入:
1
10 20 30
2
6 8 10
5 5 5
7
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
5
31 41 59
26 53 58
97 93 23
84 62 64
33 83 27
0
样例输出:
Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4: maximum height = 342
思路:
决定结果的永远是最上面的那一个立方体,可以用二元组来表示这个底面长和宽,每增加一层导致长和宽都会减少,符合DAG模型,可以套用最长路算法。
有一个问题是立方体的长和宽可能会很大,所以这里建议采用标记序号的方式来代替二元组的两个值,例如状态(3,1)表示的就是第三个立方体,高度为这组值的第一个值。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 1024
bool g[MAX][MAX];
int dp[MAX][MAX], a[MAX][5];
struct node {
int x,y,z;
}arr[MAX];
int t;
int n;
bool init() {
t = 0;
cin >> n;
if (!n)return false;
else {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= 3; j++) {
cin >> a[i][j];
}
sort(a[i], a[i] + 4);
arr[++t].x = a[i][1];
arr[t].y = a[i][2];
arr[t].z = a[i][3];
arr[++t].x = a[i][1];
arr[t].y = a[i][3];
arr[t].z = a[i][2];
arr[++t].x = a[i][2];
arr[t].y = a[i][3];
arr[t].z = a[i][1];
}
}
memset(dp, -1, sizeof(dp));
return true;
}
void creat() {
memset(g, false, sizeof(g));
for(int i=1;i<=n*3;i++)
for (int j = 1; j <= n * 3; j++) {
if (arr[i].x < arr[j].x&&arr[i].y < arr[j].y)
g[i][j] = true;
}
}
int f(int up, int down) {
int &ans = dp[up][down];
if (ans != -1)return ans;
for (int i = 1; i <= 3 * n; i++) {
if (down == i)continue;
if (g[down][i])//递归所有的连通值
ans = max(ans, f(down, i) + arr[up].z);
}
if (ans == -1)ans = arr[up].z + arr[down].z;
return ans;
}
int main(void) {
while (init()) {
creat();
int maxn = -1;
for(int i=1;i<=n*3;i++)
for (int j = 1; j <= n * 3; j++) {
if(g[i][j])maxn = max(maxn, f(i, j));
}
cout << maxn << endl;
}
system("pause");
return 0;
}
我还见到了另一种解法,说是可以用最长上升子序列的方法来解决,我是没理解,这里只贴上代码吧。在贴之前先写上最长上升子序列的代码吧,毕竟我经常忘记。
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 100
int num[MAX];
int a[MAX];
int n;
int f(int x) {
int best=0;
for (int i = 0; i < x; i++) {
num[i] = 1;
for (int j = 0; j < i; j++) {
if (a[i] > a[j]) {
num[i] = max(num[i], num[j] + 1);
best = max(best, num[i]);
}
}
}
return best;
}
int main(void) {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
cout<<f(n);
system("pause");
return 0;
}
巴比伦塔的LIS解法:
#include<bits/stdc++.h>
using namespace std;
const int n = 35;
struct block
{
int a;
int b;
int c;
}bk[n * 3];
int n;
int d[n * 3];
int cmp(block a, block b)
{
return a.a * a.b > b.a * b.b;
}
int main()
{
int cas = 1;
while (scanf("%d", &n) && n)
{
int k = 0;
int a, b, c;
for (int i = 0; i < n; i++)
{
scanf("%d%d%d", &a, &b, &c);
bk[k].a = a, bk[k].b = b, bk[k++].c = c;
bk[k].a = a, bk[k].b = c, bk[k++].c = b;
bk[k].a = b, bk[k].b = c, bk[k++].c = a;
}
sort(bk, bk + k, cmp);
int m = 0;
for (int i = 0; i < k; i++)
{
d[i] = bk[i].c;
for (int j = 0; j < i; j++)
{
if (bk[j].a > bk[i].a && bk[j].b > bk[i].b ||bk[j].b > bk[i].a && bk[j].a > bk[i].b)
{
d[i] = d[i] > d[j] + bk[i].c ? d[i] : d[j] + bk[i].c;
}
}
if (d[i] > m)
m = d[i];
}
printf("case %d: maximum height = %d\n", cas++, m);
}
}
LIS代码取自:
http://blog.csdn.net/egqawkq/article/details/78147269