我承認,這道題我做了很久,大概是三天吧……所以應該把這道題答案放出來……
啃動態規劃嘛,那肯定就是動態規劃啦!
題目大意是有N種木塊,每種無限個,有長寬高,任意兩個當底,一個當高,把這些木塊摞起來,上面的木塊長和寬都必須比下面的小,問最高能摞多高?
好 吧,這道題剛開始看到的時候我果斷看成了一個無限空間的背包問題,但是馬上我就發現了bug,如果真的是當背包做,第二重循環怎么寫啊……然后開始枚舉第 二個狀態……f[i]表示當第i個木塊為頂時的最高高度,每一個木塊都得比它下面的木塊小,仔仔細細想想就能發現一個木塊只能用三個,那么好吧,存儲的時 候一個當成三個存好了……
遇到這種情況我喜歡用結構體,因為這樣一個變量就可以存入一個木塊的所有的參數,果斷就是組合數,長寬高就那么存 就行了,而且長永遠比寬長,為了保險,以所有木塊的長為主進行排序。然后開始做,第i個木塊為頂,然后開始掃它底下的木塊,因為事先排過序了,在i下面的 木塊只能是i之前的而且寬比i小的木塊(實際上,愿意掃全場也行)。
最優子結構是當第i個為頂為最高的時候,i的下面一定存在一點k,當第 k個木塊在最頂上的時候,使得高度最高,然后以k為最底,當第i個木塊在最頂上的時候,使得高度最高,這樣一來整體高度最高。說實話,我想過當摞了前i個 木塊,使得高度最高的子結構,結果我就發現了每個木塊都有三種擺放方式,然后就是一個大bug——根本無法實現好不好……
最優子結構找到了,然后就是寫方程了哈
方程那段的代碼:
if (f[i] < f[j] + a[i].g) f[i] = f[j] + a[i].g;
a[i].g是第i個的高,j表示的是i下面的那個,每一步都要有一個初始化,就是f[i] = a[i].g。
好了……寫完了。
PS:其實這個靈感來自于磊哥的一個指導……原版是f[i, s]表示當第i個以s方式為頂的時候,最高的高度,然后我覺得木塊的變化有點高深,就干脆把一個木塊當成三個木塊了。。。
特別鳴謝:磊哥ZLGG
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
struct data
{
int x, y, z;
}a[100];
int n, i, j, tot, x, y, z, dp[100];
int max(int a, int b)
{
if (a > b) return a;
else return b;
}
int min(int a, int b)
{
if (a < b) return a;
else return b;
}
int cmp(data a, data b)
{
return a.x > b.x;
}
void add(int x, int y, int z)
{
tot++;
a[tot].x = max(x, y);
a[tot].y = min(x, y);
a[tot].z = z;
tot++;
a[tot].x = max(x, z);
a[tot].y = min(x, z);
a[tot].z = y;
tot++;
a[tot].x = max(y, z);
a[tot].y = min(y, z);
a[tot].z = x;
}
int main()
{
int t = 1;
while (cin >> n && n != 0)
{
tot = 0;
memset(dp, 0, sizeof(dp));
for (i = 1; i <= n; i++)
{
cin >> x >> y >> z;
add(x, y, z);
}
sort(a + 1, a + tot + 1, cmp);
for (i = 1; i <= tot; i++) dp[i] = a[i].z;
for (i = 2; i <= tot; i++)
for (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);
}
}
int max = 0;
for (i = 1; i <= tot; i++)
if (dp[i] > max) max = dp[i];
cout << "Case " << t++ << ": maximum height = " << max << endl;
}
return 0;
}