我承認(rèn),這道題我做了很久,大概是三天吧……所以應(yīng)該把這道題答案放出來(lái)……
啃動(dòng)態(tài)規(guī)劃嘛,那肯定就是動(dòng)態(tài)規(guī)劃啦!
題目大意是有N種木塊,每種無(wú)限個(gè),有長(zhǎng)寬高,任意兩個(gè)當(dāng)?shù)祝粋€(gè)當(dāng)高,把這些木塊摞起來(lái),上面的木塊長(zhǎng)和寬都必須比下面的小,問(wèn)最高能摞多高?
好 吧,這道題剛開(kāi)始看到的時(shí)候我果斷看成了一個(gè)無(wú)限空間的背包問(wèn)題,但是馬上我就發(fā)現(xiàn)了bug,如果真的是當(dāng)背包做,第二重循環(huán)怎么寫(xiě)啊……然后開(kāi)始枚舉第 二個(gè)狀態(tài)……f[i]表示當(dāng)?shù)趇個(gè)木塊為頂時(shí)的最高高度,每一個(gè)木塊都得比它下面的木塊小,仔仔細(xì)細(xì)想想就能發(fā)現(xiàn)一個(gè)木塊只能用三個(gè),那么好吧,存儲(chǔ)的時(shí) 候一個(gè)當(dāng)成三個(gè)存好了……
遇到這種情況我喜歡用結(jié)構(gòu)體,因?yàn)檫@樣一個(gè)變量就可以存入一個(gè)木塊的所有的參數(shù),果斷就是組合數(shù),長(zhǎng)寬高就那么存 就行了,而且長(zhǎng)永遠(yuǎn)比寬長(zhǎng),為了保險(xiǎn),以所有木塊的長(zhǎng)為主進(jìn)行排序。然后開(kāi)始做,第i個(gè)木塊為頂,然后開(kāi)始掃它底下的木塊,因?yàn)槭孪扰胚^(guò)序了,在i下面的 木塊只能是i之前的而且寬比i小的木塊(實(shí)際上,愿意掃全場(chǎng)也行)。
最優(yōu)子結(jié)構(gòu)是當(dāng)?shù)趇個(gè)為頂為最高的時(shí)候,i的下面一定存在一點(diǎn)k,當(dāng)?shù)?k個(gè)木塊在最頂上的時(shí)候,使得高度最高,然后以k為最底,當(dāng)?shù)趇個(gè)木塊在最頂上的時(shí)候,使得高度最高,這樣一來(lái)整體高度最高。說(shuō)實(shí)話,我想過(guò)當(dāng)摞了前i個(gè) 木塊,使得高度最高的子結(jié)構(gòu),結(jié)果我就發(fā)現(xiàn)了每個(gè)木塊都有三種擺放方式,然后就是一個(gè)大bug——根本無(wú)法實(shí)現(xiàn)好不好……
最優(yōu)子結(jié)構(gòu)找到了,然后就是寫(xiě)方程了哈
方程那段的代碼:
if (f[i] < f[j] + a[i].g) f[i] = f[j] + a[i].g;
a[i].g是第i個(gè)的高,j表示的是i下面的那個(gè),每一步都要有一個(gè)初始化,就是f[i] = a[i].g。
好了……寫(xiě)完了。
PS:其實(shí)這個(gè)靈感來(lái)自于磊哥的一個(gè)指導(dǎo)……原版是f[i, s]表示當(dāng)?shù)趇個(gè)以s方式為頂?shù)臅r(shí)候,最高的高度,然后我覺(jué)得木塊的變化有點(diǎn)高深,就干脆把一個(gè)木塊當(dāng)成三個(gè)木塊了。。。
特別鳴謝:磊哥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;
}