首先这道题目先要理解题目的意思。

用一些方块堆塔,给出的每种方块个数是无限的,只有满足长宽都小于下面一个方块的方块才能摆上去。

首先这道题需要一个转化。

每个方块有3个不同的面,每个面长宽交换,一共每个方块最多有6种情况。

X Y Z

1 2 3

2 1 3

3 1 2

1 3 2

2 3 1

3 2 1

如果长宽高有相同的部分还可以减少一些情况

然后对面积,长,宽,从小到大排序。

这步做完dp的准备才算完成。

下面分析dp部分。

如果不用dp,用贪心先试试,先把最大的面积放在下面,然后循环面积比他小的,如果满足长宽都小就摆上去,循环一遍摆完为止。

for(n->1)

{

for(n-1->1)

{

max +=z;

}

}

看上去貌似是可以的,但是其实是不行的,因为你摆了n-1之后,能不能摆n-3了,如果不能,你就不知道n-3和n-4的组合是不是比摆n-1要好了,所以贪心失败。

dp试试

从小到大,先摆最小的,然后用下一个,循环比所有他小的(之前已经摆好了),其中dp【】数据最优的,保存在当前dp【】数组中并且加上当前的方块高度。

状态转移方程

dp【now】 = max(for(now->1)循环中dp【】值最大的) + bolck【now】;

初始值

全部为0

下面给出dp的代码和贪心的代码

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm> using namespace std;
/*dp,hdu1069*/ int dp[];//动态规划的数组 struct block
{
int x;//长
int y;//宽
int z;//高
int s;//面积
}; int cmp(const void * a, const void * b)
{
struct block * p2 = (struct block *)a;
struct block * p1 = (struct block *)b; if(p1->s != p2->s)
return p2->s - p1->s;
else if(p1->x != p2->x)
return p2->x - p1->x;
else
return p2->y - p1->y;
} int main()
{
int n;//方块个数
int i,j;//循环变量
int number=;//记录可行方块数,一个方块最多有6钟可行方案
int maxNumber=;//记录结果
int reslut=;//记录次数
int x,y,z;//用户输入
int tempMax,tempX,tempY;//临时变量 struct block blocks[];//保存所有情况方块
while (true)
{
cin>>n;
if(n==)
break; number=;
for (i = ; i < n; i++)
{
cin>>x>>y>>z; //记录6钟情况
if(x==y&&y==z)
{
blocks[number].x = x;
blocks[number].y = y;
blocks[number].z = z;
blocks[number].s = x*y;
number++;
}
else
{
if(x==y)
{
blocks[number].x = x;
blocks[number].y = y;
blocks[number].z = z;
blocks[number].s = x*y;
number++;
}
else
{
blocks[number].x = x;
blocks[number].y = y;
blocks[number].z = z;
blocks[number].s = x*y;
number++; blocks[number].x = y;
blocks[number].y = x;
blocks[number].z = z;
blocks[number].s = x*y;
number++;
} if(x==z)
{
blocks[number].x = x;
blocks[number].y = z;
blocks[number].z = y;
blocks[number].s = x*z;
number++;
}
else
{
blocks[number].x = x;
blocks[number].y = z;
blocks[number].z = y;
blocks[number].s = x*z;
number++; blocks[number].x = z;
blocks[number].y = x;
blocks[number].z = y;
blocks[number].s = x*z;
number++;
} if(y==z)
{
blocks[number].x = z;
blocks[number].y = y;
blocks[number].z = x;
blocks[number].s = y*z;
number++;
}
else
{
blocks[number].x = z;
blocks[number].y = y;
blocks[number].z = x;
blocks[number].s = y*z;
number++; blocks[number].x = y;
blocks[number].y = z;
blocks[number].z = x;
blocks[number].s = y*z;
number++;
}
}
} //对于s-x-y小到大排序所有方块
qsort(blocks, number, sizeof(block), cmp); maxNumber = ;
tempMax=;
dp[] = blocks[].z;
maxNumber = dp[];
for (i = ; i < number; i++)
{
dp[i]=blocks[i].z;
tempMax=;
tempX=blocks[i].x;
tempY=blocks[i].y; for (j = i-; j >= ; j--)
{
if(tempX > blocks[j].x && tempY > blocks[j].y)
{
if(tempMax < dp[j])
tempMax=dp[j];
}
} dp[i] += tempMax;
if(dp[i] > maxNumber)
maxNumber=dp[i];
} printf("Case %d: maximum height = %d\n",reslut,maxNumber);
reslut++;
}
return ;
}

贪心

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm> using namespace std;
/*贪心,失败,hdu1069*/ struct block
{
int x;//长
int y;//宽
int z;//高
int s;//面积
}; int cmp(const void * a, const void * b)
{
struct block * p1 = (struct block *)a;
struct block * p2 = (struct block *)b; if(p1->s != p2->s)
return p2->s - p1->s;
else if(p1->x != p2->x)
return p2->x - p1->x;
else
return p2->y - p1->y;
} int main()
{
int n;//方块个数
int i,j;//循环变量
int number=;//记录可行方块数,一个方块最多有6钟可行方案
int maxNumber=;//记录结果
int reslut=;//记录次数
int x,y,z;//用户输入
int tempMax,tempX,tempY; struct block blocks[];
while (true)
{
cin>>n;
if(n==)
break; number=;
for (i = ; i < n; i++)
{
cin>>x>>y>>z; //记录6钟情况
if(x==y&&y==z)
{
blocks[number].x = x;
blocks[number].y = y;
blocks[number].z = z;
blocks[number].s = x*y;
number++;
}
else
{
if(x==y)
{
blocks[number].x = x;
blocks[number].y = y;
blocks[number].z = z;
blocks[number].s = x*y;
number++;
}
else
{
blocks[number].x = x;
blocks[number].y = y;
blocks[number].z = z;
blocks[number].s = x*y;
number++; blocks[number].x = y;
blocks[number].y = x;
blocks[number].z = z;
blocks[number].s = x*y;
number++;
} if(x==z)
{
blocks[number].x = x;
blocks[number].y = z;
blocks[number].z = y;
blocks[number].s = x*z;
number++;
}
else
{
blocks[number].x = x;
blocks[number].y = z;
blocks[number].z = y;
blocks[number].s = x*z;
number++; blocks[number].x = z;
blocks[number].y = x;
blocks[number].z = y;
blocks[number].s = x*z;
number++;
} if(y==z)
{
blocks[number].x = z;
blocks[number].y = y;
blocks[number].z = x;
blocks[number].s = y*z;
number++;
}
else
{
blocks[number].x = z;
blocks[number].y = y;
blocks[number].z = x;
blocks[number].s = y*z;
number++; blocks[number].x = y;
blocks[number].y = z;
blocks[number].z = x;
blocks[number].s = y*z;
number++;
}
}
} qsort(blocks, number, sizeof(block), cmp); maxNumber = ;
tempMax=;
tempX=;
tempY=;
for (i = ; i < number; i++)
{
tempMax=blocks[i].z;
tempX=blocks[i].x;
tempY=blocks[i].y;
for (j = i+; j < number; j++)
{
if(tempX > blocks[j].x && tempY > blocks[j].y)
{
tempX=blocks[j].x;
tempY=blocks[j].y;
tempMax += blocks[j].z;
}
}
if(tempMax > maxNumber)
maxNumber=tempMax;
} printf("Case %d: maximum height = %d\n",reslut,maxNumber);
reslut++;
}
return ;
}

经过实践,贪心可以满足前几组数据,但是最后一组数据就GG了

而且贪心和dp的效率在这里均为O(NlogN + N!)所以并没有快。

再一次证明dp确实很多时候比贪心好用。

但是其实最重要的是在dp之前对题目的分析,要把一个题目抽象到一组数,这个才是需要特别去考虑的事情,如果之前都想不到的话是肯定得不到最后的答案的。

动态规划2-----hdu1069的更多相关文章

  1. HDU-1069 Monkey and Banana DAG上的动态规划

    题目链接:https://cn.vjudge.net/problem/HDU-1069 题意 给出n种箱子的长宽高 现要搭出最高的箱子塔,使每个箱子的长宽严格小于底下的箱子的长宽,每种箱子数量不限 问 ...

  2. 增强学习(三)----- MDP的动态规划解法

    上一篇我们已经说到了,增强学习的目的就是求解马尔可夫决策过程(MDP)的最优策略,使其在任意初始状态下,都能获得最大的Vπ值.(本文不考虑非马尔可夫环境和不完全可观测马尔可夫决策过程(POMDP)中的 ...

  3. 简单动态规划-LeetCode198

    题目:House Robber You are a professional robber planning to rob houses along a street. Each house has ...

  4. 动态规划 Dynamic Programming

    March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...

  5. 动态规划之最长公共子序列(LCS)

    转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...

  6. C#动态规划查找两个字符串最大子串

     //动态规划查找两个字符串最大子串         public static string lcs(string word1, string word2)         {            ...

  7. C#递归、动态规划计算斐波那契数列

    //递归         public static long recurFib(int num)         {             if (num < 2)              ...

  8. 动态规划求最长公共子序列(Longest Common Subsequence, LCS)

    1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...

  9. 【BZOJ1700】[Usaco2007 Jan]Problem Solving 解题 动态规划

    [BZOJ1700][Usaco2007 Jan]Problem Solving 解题 Description 过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地 ...

随机推荐

  1. C#第四天

    2.类语法:[public] class 类名{    字段;    属性;    方法;}写好了一个类之后,我们需要创建这个类的对象,那么,我们管创建这个类的对象过程称之为类的实例化.使用关键字 n ...

  2. Oracle Day05 集合与数据处理

    1.集合 --集合操作: 并集.交集.差. select deptno,job,sum(sal) from emp group by deptno,job union select deptno,to ...

  3. python多线程,多进程

    线程是公用内存,进程内存相互独立 python多线程只能是一个cpu,java可以将多个线程平均分配到其他cpu上 以核为单位,所以GIL(全局锁,保证线程安全,数据被安全读取)最小只能控制一个核,很 ...

  4. hadoop性能测试命令

    1.测试hadoop写的速度向HDFS文件系统中写入数据,10个文件,每个文件10MB,文件存放到/benchmarks/TestDFSIO/io_data中hadoop  jar share/had ...

  5. 《JavaScript高级程序设计》读书笔记 ---if语句

    if语句 大多数编程语言中最为常用的一个语句就是if 语句.以下是if 语句的语法:if (condition) statement1 else statement2其中的condition(条件)可 ...

  6. ios ViewController的生命周期分析和基本使用逻辑

    按结构可以对iOS的所有ViewController分成两类:1.主要用于展示内容的ViewController,这种ViewController主要用于为用户展示内容,并与用户交互,如UITable ...

  7. hdu_1072_Nightmare(BFS)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1072 题意:给你一个地图,让你在炸弹爆之前找到出口,最初炸弹设定为6,每走一格需要1,中途有地方能让炸 ...

  8. LeetCode OJ 118. Pascal's Triangle

    Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Retur ...

  9. android网络编程之HttpUrlConnection的讲解--DownLoadManager基本用法

    1.DownLoadManager是Android用系统服务(Service)的方式来优化处理长时间的下载操作的一个工具类.避免了我们去处理多线程,通知栏等等. 2.不要忘记添加权限 <uses ...

  10. JSP基本语法--包含指令<%@include file="路径"%> <jsp:include page>

    包含指令,真正改变的地方只有具体内容处: 方法1: 在每个jsp页面(HTML)都包含工具栏,头部信息,尾部信息,具体内容 方法2: 将工具栏,头部信息,尾部信息都分成各个独立的文件,使用的时候直接导 ...