UVA 437 The Tower of Babylon【LIS变形+O(n2)算法】

题目大意:给出塔的长宽高(立方体),每个塔长宽高可任意且无限用,要求将所以可能的塔堆起来,题意要求上边的塔的长宽必须分别小于下面的长宽。

                    最后求出满足题意的塔的最大高度。

解题策略:每个立方体,长宽高因为可以互换,所以可以将每一个立方体可拓展为3! = 6种立方体,全部存储,并按照底面积降序排列,然后以题意要求求出变形LIS。

                    详见注释。

/*
   UVA 437 The Tower of Babylon
   AC by J.Dark
   ON 2013/4/7
   Time 0.012s
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;
const int maxn = 200;
/
struct St{
   int length, width, height;
   int area;
}Stone[maxn];
int stCount=0, count1=0, testCase, maxHeight;
/
void Input(){
   count1++;
   int temp[3];
   //默认塔的底座为底面积无穷大,但高度为0
   //用来使第一个塔可以进入O(n2)算法 
   Stone[0].length = INT_MAX;
   Stone[0].width = INT_MAX;
   Stone[0].height = 0;
   Stone[0].area = INT_MAX;
   //拓展一个塔为六个塔 
   for(int i=1; i<=testCase; i++){
      cin >> temp[0] >> temp[1] >> temp[2];
      Stone[++stCount].length = temp[0];
      Stone[stCount].width = temp[1];
      Stone[stCount].height = temp[2];
      Stone[stCount].area = temp[0]*temp[1];
      //next_permutation为STL里的全排列函数,用途为形成当前排列的下一个全排列,若存在返回真,否则假 
      //注意当输入“3 2 1”,该函数不再生成全排列,但返回最小的排列即“1 2 3” 
      while(next_permutation(temp, temp+3));  //生成最小的全排列 
      while(next_permutation(temp, temp+3))  //拓展一塔为六塔,长宽高互换为新塔,即3!种 
      {
         Stone[++stCount].length = temp[0];
         Stone[stCount].width = temp[1];
         Stone[stCount].height = temp[2];
         Stone[stCount].area = temp[0]*temp[1];
      } 
   }
}

int cmp(St x, St y){
   return x.area > y.area;
}

void Solve(){
     //按底面积降序排列 
     sort(Stone+1, Stone+stCount+1, cmp);
     int Height[maxn]; //到当前元素为止,塔的最大高度 
     for(int i=0; i<=stCount; i++)   Height[i] = 0;
     for(int i=0; i<=stCount; i++){
        for(int j=0; j<i; j++){
          //判断i是否可以底面积比i大的塔之上 
          if(Stone[i].length < Stone[j].length && Stone[i].width < Stone[j].width){
             if(Height[j]+Stone[i].height > Height[i]){ //如果可以放上去 
                Height[i] = Height[j]+Stone[i].height; //更新 
             }
          }
        }
     }
     maxHeight = 0;
     for(int i=1; i<=stCount; i++)
        maxHeight = max(maxHeight, Height[i]);
     printf("Case %d: maximum height = %d\n", count1, maxHeight);
     stCount = 0;
}

/
int main(){
    while(cin >> testCase && testCase)
    {
       Input();
       Solve();
    }           
    
    //system("pause");
    return 0;
}


附朱神牛的范例代码,用priority_queue(优先队列),并且一个塔拓展三个塔,以高度为拓展条件。

/*
UVa437 - The Tower of Babylon
Solved by Guojin Zhu
Run Time 0.008s
AC on April 5, 2013
*/
#include<iostream>
#include<queue>
#include<algorithm>
#include<climits>
using namespace std;
//
struct Block{
    int longBase;
    int shortBase;
    int height;
    Block(int a = 0, int b = 0, int c = 0){longBase = a; shortBase = b; height = c;}
    friend bool operator < (Block b1, Block b2){// cannot put b1 onto b2
        return b1.longBase < b2.longBase;
    }
    friend bool operator > (Block b1, Block b2){// can put b2 onto b1
        return (b1.longBase > b2.longBase) && (b1.shortBase > b2.shortBase);
    }
};
class BabylonTower{
private:
    priority_queue<Block> sequence; //blocks sorted by < from large to small
    int maxHeight;
public:
    void initial();
    void readCase(int);
    void computing();
    void outResult(int);
};
void BabylonTower::initial(){
    while(!sequence.empty()){//clear the sequence
        sequence.pop();
    }
    maxHeight = 0;
}
void BabylonTower::readCase(int n){
    int x, y, z;
    while(n--){
        cin >> x >> y >> z;
        sequence.push(Block(max(x, y), min(x, y), z));
        sequence.push(Block(max(y, z), min(y, z), x));
        sequence.push(Block(max(z, x), min(z, x), y));
    }
}
void BabylonTower::computing(){
    queue<Block> q;
    Block b, cur;
    int qsize, mHeight;
    q.push(Block(INT_MAX, INT_MAX, 0)); //for the sentinel
    while(!sequence.empty()){//BFS
        //cout << sequence.top().longBase << ' ' << sequence.top().shortBase << ' ' << sequence.top().height << endl;
        b = sequence.top(); 
        sequence.pop();
        qsize = q.size();
        mHeight = b.height;
        while(qsize--){
            cur = q.front();
            q.pop();
            q.push(cur);
            if(cur > b){
                mHeight = max(mHeight, cur.height + b.height);
            }
        }
        b.height = mHeight; // new height
        q.push(b);
    }
    while(!q.empty()){
        maxHeight = max(maxHeight, q.front().height);
        q.pop();
    }
}
void BabylonTower::outResult(int c){
    cout << "Case " << c << ": maximum height = " << maxHeight << endl;
}
//
int main(){
    BabylonTower bt;
    int n, c = 1;
    while((cin >> n) && n){
        bt.initial();
        bt.readCase(n);
        bt.computing();
        bt.outResult(c++);
    }
    return 0;
}
/*
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
-------------
OUTPUT
Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4: maximum height = 342
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值