Uva 437 The Tower of Babylon

题目大意

你有N种石头,给定石头的长宽高,每种石头有无限块,石头的叠放顺序是上一个石头的长宽比下一个石头的长宽要严格大于,要求叠起来的石头高度最大值。1<=n<=30。

思路

方法一:拓扑序+dp。动规方程dp[i]=max(dp[i],dp[j]+stone[i]),dp方向是拓扑序。这题之所以能用拓扑序+dp是因为每种石头只能放一次,虽说有无限块,但是限于叠放顺序的原则是不能多放的。而输入的石头可以有三种放法,因此石头种数时N*3,然后构建图并且以拓扑序进行dp。
方法二:DAG+DP。这种做法也是需要构建一个图(a>b则连起一条自a向b的有向边),原理好像和拓扑序一致。不过有一点是遍历方向,DAG里点是“去中心化”的,对每个点都进行dp更新。而上一种做法是按照拓扑序来进行的,是有优先级的。

代码(方法一)

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>

using namespace std;
struct Blocks{
    int x,y,z;
};
int n;
vector<Blocks> box;
queue<int> q;
bool graph[105][105];
int v[105],in[105];
int main()
{
    //freopen("1.txt","r",stdin);
    //freopen("2.txt","w",stdout);

    int x,y,z,cnt=1;
    while(scanf("%d",&n)!=EOF&&n){
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&x,&y,&z);
            Blocks a;
            a.x=x;a.y=y;a.z=z;
            box.push_back(a);
            a.x=y;a.y=z;a.z=x;
            box.push_back(a);
            a.x=z;a.y=x;a.z=y;
            box.push_back(a);
        }
        for(int i=0;i<box.size();i++){
            for(int j=0;j<box.size();j++){
                if(i==j)continue;
                if(box[i].x>box[j].x&&box[i].y>box[j].y){
                        graph[i][j]=1;
                        in[j]++;
                }
                else if(box[i].x>box[j].y&&box[i].y>box[j].x){
                        graph[i][j]=1;
                        in[j]++;
                }
            }
        }
        int ans=0;
        for(int i=0;i<box.size();i++){
            //printf("%d %d %d %d\n",in[i],box[i].x,box[i].y,box[i].z);
            if(in[i]==0){
                q.push(i);
                v[i]=box[i].z;
                ans=max(ans,v[i]);
            }
        }
        //printf("\n");
        while(!q.empty()){
            int head=q.front();
            q.pop();

            //printf("%d %d %d\n",box[head].x,box[head].y,box[head].z);

            //printf("in[%d]=%d %d %d %d\n",head,in[head],box[head].x,box[head].y,box[head].z);

            for(int i=0;i<box.size();i++){
                if(graph[head][i]){
                    in[i]--;
                    v[i]=max(v[i],v[head]+box[i].z);
                    ans=max(ans,v[i]);
                    if(in[i]==0)q.push(i);
                }
            }
        }
        printf("Case %d: maximum height = %d\n",cnt++,ans);
        box.clear();
        memset(graph,0,sizeof(graph));
        memset(v,0,sizeof(v));
        memset(in,0,sizeof(in));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值