Monkey and Banana(DAG上的动态规划问题)

Monkey and Banana

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 8122    Accepted Submission(s): 4194

Problem Description

A group of researchers are designing an experiment to test the IQ of a monkey. They will hang a banana at the roof of a building, and at the mean time, provide the monkey with some blocks. If the monkey is clever enough, it shall
be able to reach the banana by placing one block on the top another to build a tower and climb up to get its favorite food.

The researchers have n types of blocks, and an unlimited supply of blocks of each type. Each type-i block was a rectangular solid with linear dimensions (xi, yi, zi). A block could be reoriented so that any two of its three dimensions determined the dimensions
of the base and the other dimension was the height.

They want to make sure that the tallest tower possible by stacking blocks can reach the roof. The problem is that, in building a tower, one block could only be placed on top of another block as long as the two base dimensions of the upper block were both strictly
smaller than the corresponding base dimensions of the lower block because there has to be some space for the monkey to step on. This meant, for example, that blocks oriented to have equal-sized bases couldn‘t be stacked.

Your job is to write a program that determines the height of the tallest tower the monkey can build with a given set of blocks.

Input

The input file will contain one or more test cases. The first line of each test case contains an integer n,

representing the number of different blocks in the following data set. The maximum value for n is 30.

Each of the next n lines contains three integers representing the values xi, yi and zi.

Input is terminated by a value of zero (0) for n.

Output

For each test case, print one line containing the case number (they are numbered sequentially starting from 1) and the height of the tallest possible tower in the format "Case case: maximum height = height".

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

题意:
    有一群闲得无聊的科学家打算测试猴子的IQ,科学家想出了一个方法来测试猴子们. 首先科学家把猴子最喜欢吃的香蕉放在屋顶,在给它们n个种类的石块,
然后看看猴子们能不能利用这些石块拿到香蕉. 石块是一个矩形立方体,可以任意摆放,一个石块可以放在另一个石块的前提是石块的宽和长要严格大于另一个石块
的宽和长. 猴子现在叠石块,结果问猴子所能叠出的石块的最大高度为多少.

题解:
    典型的DAG上的动态规划问题,一个石块可以叠在另一个石块时,就连一条有向边,然后就记忆化搜索从i个石块开始搜索的最大高度.

AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <cmath>
#include <cctype>

using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int M = 200;
int to,G[M][M],d[M];

struct Node
{
    int x,y,z;
    bool operator < (const Node &a) const
    {
        return a.x > x || (a.x == x && a.y > y);
    }
} p[M];

void make(int a,int b,int c) //石块可以有六种摆放方法;
{
    p[to].x = a;
    p[to].y = b;
    p[to++].z = c;
    p[to].x = b;
    p[to].y = a;
    p[to++].z = c;
    p[to].x = a;
    p[to].y = c;
    p[to++].z = b;
    p[to].x = c;
    p[to].y = a;
    p[to++].z = b;
    p[to].x = b;
    p[to].y = c;
    p[to++].z = a;
    p[to].x = c;
    p[to].y = b;
    p[to++].z = a;
}

int dp(int i) //记忆化搜索;
{
    int& ans = d[i];
    if(ans) return ans;
    ans = p[i].z;
    for(int j = 0; j < to; j++)
        if(G[i][j]) ans = max(ans,dp(j) + p[i].z);
    return d[i] = ans;
}

void debug() //调试用的;
{
    for(int i = 0; i < to; i++)
        printf("%d %d %d\n",p[i].x,p[i].y,p[i].z);
}

int main()
{
    int n,Max,cnt = 0;
    while(~scanf("%d",&n) && n)
    {
        to = Max = 0;
        memset(G,0,sizeof(G));
        memset(d,0,sizeof(d));
        while(n--)
        {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            if(a == b && b == c)
            {
                p[to].x = a;
                p[to].y = b;
                p[to++].z = c;
                continue;
            }
            make(a,b,c);
        }
        //debug();
        for(int i = 0; i < to; i++)
            for(int j = 0; j < to; j++)
                if(i != j)
                    if(p[i].x < p[j].x && p[i].y < p[j].y) G[i][j] = 1; //建图
        for(int i = 0; i < to; i++)
            Max = max(Max,dp(i));
        printf("Case %d: maximum height = %d\n",++cnt,Max);
    }
    return 0;
}
时间: 2024-08-29 08:09:15

Monkey and Banana(DAG上的动态规划问题)的相关文章

ACM:DAG上的动态规划------硬币问题

ExecutorService 建立多线程线程池的步骤: 线程池的作用: 线程池作用就是限制系统中执行线程的数量. 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果:少了浪费了系统资源,多了造成系统拥挤效率不高.用线程池控制线程数量,其他线程排队等候.一个任务执行完毕,再从队列的中取最前面的任务开始执行.若队列中没有等待进程,线程池的这一资源处于等待.当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了:否则进入等待队列. 为什么要用线程池: 1.减少了创建和

UVa 103 Stacking Boxes --- DAG上的动态规划

UVa 103 题目大意:给定n个箱子,每个箱子有m个维度, 一个箱子可以嵌套在另一个箱子中当且仅当该箱子的所有的维度大小全部小于另一个箱子的相应维度, (注意箱子可以旋转,即箱子维度可以互换),求最多能套几个箱子. 第一行输入为n,m,之后是n行m维的箱子 解题思路:嵌套关系是二元关系,因此这题即在DAG上做动态规划, 只不过将二维的判断改成了n维,其他不变. 详细看考:DAG上的动态规划之嵌套矩形  (ps:这题可以理解成嵌套m边形) /* UVa 103 Stacking Boxes --

嵌套矩形——DAG上的动态规划

有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 题目描述: 有n个矩形,每个矩形可以用两个整数a,b描述,表示它的长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d,或者b<c,a<d(相当于把矩形X旋转90°).例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)内.你的任务是选出尽可能多的矩形排成一行.使得除了最后一个之外,每个矩形都

DP入门(2)——DAG上的动态规划

有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.DAG模型 [嵌套矩形问题] 问题:有n个矩形,每个矩形可以用两个整数a.b描述,表示它的长和宽.矩形X(a , b)可以嵌套在矩形Y(c , d)中当且仅当a<c,b<d,或者b<c,a<d(相当于把矩形X旋转90°).例如(1,5)可以嵌套在(6, 2)内,但不能嵌套在(3, 4)内.你的任务是选出尽可能多的矩形排

The Tower of Babylon UVA - 437 DAG上的动态规划

题目:题目链接 思路:每个方块可以用任意多次,但因为底面限制,每个方块每个放置方式选一个就够了,以x y为底 z 为高,以x z为底 y 为高,以y z为底 x为高,因为数据量很小,完全可以把每一种当成DAG上的一个结点,然后建图找最长路径. AC代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <cs

[USACO][DAG上的动态规划]Sorting A Three-Valued Sequence

好美的图论,真的 light up my life!题意: 给出一个只含有若干1,2,3的数列,我们可以两两交换数列元素:要求输出让这个数列不减的最小交换次数. 思路: 首先看起来很像冒泡.....然鹅要最少交换次数——显然不是模拟冒泡了. 开始用深搜来着,显然没办法剪枝,果断T掉.这个时候就要想一想图论了. 想起来leetcode周赛的1247这道题.题目说的是有两个在{x,y}上相同长度的字符串,我们可以在两个字符串之间任选字符交换.求第一个字符串变成第二个字符串所需要的最小交换次数,有一点

DAG上的动态规划

UVA1025 分析:因为时间是单向流逝的,是天然的"序",所以影响决策的只有当前时间和所处的决策.dp[i][j],表示在第i分钟时,处于第j个车站,最少还需要多少等待时间,因此其等待时间就有站原地等待,乘坐从左到右的车,乘坐从右到左的车,三个状态来决定. 1 #include "iostream" 2 #include "cstdio" 3 #include "cstring" 4 #include "strin

[CF225C] Barcode (简单DAG上dp)

题目链接:http://codeforces.com/problemset/problem/225/C 题目大意:给你一个矩阵,矩阵中只有#和.两种符号.现在我们希望能够得到一个新的矩阵,新的矩阵满足每一列都只有一种符号,并且连续相同符号的列数在区间[x,y]之间. 解: 现将列中的点统计出来,然后就是枚举把列数在x到y之间的需要更改为点的统计出来.这些点染上白色. 然后再将列数在x到y之间的需要更改为井号的点数统计出来,这些点染成黑色. 接下来就是DAG上的动态规划了,dp[i]代表从i到终点

DAG上动态规划

很多动态规划问题都可以转化为DAG上的最长路,最短路,或路径计数问题. 硬币问题: 有N中硬币,面值分别为v1,v2,v3,……vn,每种都无穷多,给定非负整数S,可以选用多少个硬币,使他们的总和恰好为S.输出硬币数目的最小值和最大值. 解:每种面值看作一个点,表示:还需要凑足的面值.则开始状态为S,目标状态为0:若当前状态为i,当使用硬币j后,状态转为i-v[j]. 代码说明好了. 1 #include <iostream> 2 #include <cstdio> 3 #incl