1. 程式人生 > >【DP】【Uva437】UVA437 The Tower of Babylon

【DP】【Uva437】UVA437 The Tower of Babylon

塊存儲 ostream return www 轉移 targe cas solution ++

傳送門

Description

技術分享圖片

Input

技術分享圖片

Output

技術分享圖片

Sample Input

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

Sample Output

Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4
: maximum height = 342

Hint

  n<=30。

Solution

  一眼看出這是個DAG上的DP,一個信息分成三個方塊存儲。然後開始讀入,拓撲,輸出,過樣例,提交,WA……

   這裏的關鍵是拓撲序應該怎麽求。首先我的比較函數寫法如下:

inline bool cmp(const Block &a,const Block &b) {
    return (a.l1<b.l1&&a.l2<b.l2)||(a.l2<b.l1&&a.l1<b.l2);
}

   然後由於sort的一些問題,這麽寫會掛掉。hack數據:我丟了……

   然後就來想想這個拓撲怎麽求。

   考慮二元組(a,b)表示方塊的長和寬,由於長和寬的順序對放置無影響,所以不妨設a>=b。

   引理:若1能放在2上面,則2不能放在1上面。

    證明:  由題設,a1>a2,b1>b2。

         當2能放在1上面,a2>a1,b2>b1。矛盾。引理得證。

   定理:若a1+b1=a2+b2,則這兩個方塊不能疊放。

   證明:不妨設a1>=a2。當a1==a2時,b1==b2。又a>b。顯然不成立

        當a1>a2,則b1<b2。故不成立。

   定理:當且僅當a1+b1<a2+b2時,方塊2可能疊放在1上面。

   證明:已證相等時不成立,現在證明前者大於後者時不成立。

       前者大於後者時,a1+b1>a2+b2。

          當a1<a2,顯然b1>b2。不成立。

          當a1>a2,b1>b2,由引理,不成立。

          當a1>a2,b1<b2,顯然不成立。

       下面證明可能性

          當a1<a2,b1<b2時,滿足原式,可以疊放。

       定理得證。

   由上述定理知,設si=ai+bi,則f[i]只可能由{f[j]|sj<si}轉移得到。故將a+b得值設為階段,進行轉移。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define maxn 100

inline void qr(int &x) {
    char ch=getchar();int f=1;
    while(ch>9||ch<0)    {
        if(ch==-)    f=-1;
        ch=getchar();
    }
    while(ch>=0&&ch<=9)    x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x*=f;
    return;
}

inline int max(const int &a,const int &b) {if(a>b) return a;else return b;}
inline int min(const int &a,const int &b) {if(a<b) return a;else return b;}
inline int abs(const int &x) {if(x>0) return x;else return -x;}

inline void swap(int &a,int &b) {
    int c=a;a=b;b=c;return;
}

int n,a,b,c,frog[maxn];

struct Block {
    int h,l1,l2;
};
Block block[maxn];int top,cnt,ans;

inline void add(int x,int y,int z) {
    block[++top].h=x;block[top].l1=y;block[top].l2=z;
    if(block[top].l1<block[top].l2)    swap(block[top].l2,block[top].l1);
    block[++top].h=y;block[top].l1=x;block[top].l2=z;
    if(block[top].l1<block[top].l2)    swap(block[top].l2,block[top].l1);
    block[++top].h=z;block[top].l1=x;block[top].l2=y;
    if(block[top].l1<block[top].l2)    swap(block[top].l2,block[top].l1);
}

void clear() {
    std::memset(block,0,sizeof block);top=0;
    std::memset(frog,0,sizeof frog);ans=0;
}

inline bool cmp(const Block &a,const Block &b) {
    int sa=a.l1+a.l2,sb=b.l1+b.l2;
    return sa<sb;
}

inline bool judge(const Block &a,const Block &b) {
    return (a.l1<b.l1&&a.l2<b.l2)||(a.l2<b.l1&&a.l1<b.l2);
}

int main() {
    qr(n);
    while(n) {
        clear();
        for(int i=1;i<=n;++i) {
            a=b=c=0;qr(a);qr(b);qr(c);
            add(a,b,c);
        }
        std::sort(block+1,block+1+top,cmp);
        for(int i=1;i<=top;++i) {
            int &emm=block[i].h;
            frog[i]=emm;
            for(int j=1;j<i;++j) {
                if(judge(block[j],block[i])) frog[i]=max(frog[i],frog[j]+emm);
            }
            ans=max(ans,frog[i]);
        }
        printf("Case %d: maximum height = %d\n",++cnt,ans);
        n=0;qr(n);
    }
    return 0;
}

Summary

  1、寫完dp和爆搜對拍一下!!!

   2、dp中階段可能是一個非常難以想象的量,比如二元組的求和,在求拓撲序時可以考慮一些特殊性質。

   3、求拓撲序慎用sort

【DP】【Uva437】UVA437 The Tower of Babylon