poj 3044 和 3250 栈的使用

poj 3044:

3044(贪心,单调栈)

与3250一起做。
这道题主要是题意难懂,看详细的分析。
题意:以坐标的形式给出一张图,表示一些楼房的正视图,求出楼房的最少个数。
题意理解:
(1)给出的坐标是高度发生变化时的楼高坐标,上面的例图中,一个宽度为27的楼面正视图其实用10个发生高度变化时的坐标就能决定,如下:
x=1时,楼高y=1;x=2-4,y=2;x=5时,y=1;x=6-7时,y=3;x=8-10时,y又变成1;x=11-14时,y=0(这时从正视图来看,发生了中断);x=15-16时,y=1;x=17-19时,y=3;x=20-21时,y=2;x=23-27时,y=1;
(2)题目的要求与小学常做的立方体问题很像,看过去是个平面图,如果都是一片等高的,那就是一个建筑,如果高度发生变化,就想象是两个建筑,矮的在前面一排连续,高的在后面一排连续。(很容易想到一个贪心方法,那就是尽量把矮的楼房放在高的楼房的前面,即连续的等高的一些"X"我们把它视为一个,比如xxxxx就是一个高度为1的建筑。)
(3)怎么算最少的建设数呢:比如上图中:
只从前1到5这几个坐标,代表着最少有2个建筑物,即:高度为1的在第一排(x=1-2-3-4-5),高度为2的在第二排(x=2-4),从远处看就是这样的阴影效果。
那么,以此类推,算法思路:
(1)初始高度为0,见到有差异的高度,如(1,1),把1进栈(0、1);之后是2,进栈(0、1、2),连续的2不再进栈(因为看作一个建筑);之后又是高度1,此时说明连续高度为2的发生中断,可确定有一个建筑,计数器加1,把高度2弹出(表示这个建筑已经考虑过了,而留在栈内的是还未考虑的);之后高度3,进栈为(0、1、3),之后连续的高度3不进;之后高度1,又发生中断,确定找到一片高度为3的建筑,弹出3,计数器加1,新的高度1与栈顶高度一样,说明与已有的一些可以构成连续高度为1的楼,不进栈;指导高度为0,说明高度为1的连续楼层中断,确定高度为1的建筑,弹出1,计数器加1。此时,到达x坐标为10;余下的以此类推。
具体算法:
维护一个Y坐标单增的栈,从左到右读入每个坐标,将Y坐标与栈顶坐标比较:
若Y==栈顶坐标,那么接着读下面一个坐标
若Y>栈顶坐标,那么把Y坐标加入栈成为新的栈顶
若Y<栈顶坐标,那么弹出栈顶坐标,且ans+1表示前面一段以栈顶元素为共同高度的X作为一个楼房;
由题目可以看出,w(也就是正视图的宽度)和横坐标是没有用的,只需要以此读入高度y,然后进栈比较。

Ac 的两处修改:
(1) 循环的时候到n结束而不是n-1
(2) 的使用:while(scanf(“%d%d”,&n,&w) 或 != EOF
(3)EOF

在C语言中,或更精确地说成C标准函数库中表示文件结束符(end of file)。在while循环中以EOF作为文件结束标志,这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~255,不可能出现-1,因此可以用EOF作为文件结束标志。
C语言中,EOF常被作为文件结束的标志。还有很多文件处理函数处错误后的返回值也是EOF,因此常被用来判断调用一个函数是否成功。
while(~scanf("%d",&n))
<=> while(scanf("%d",&n)!=EOF)
1.正常输入的时候,scanf返回输入的数字如1,2,3等等,对这些数字取非,不会成为0,就会执行循环;
2.错误输入指的就是没有输入的时候,scanf返回的是EOF(End Of File),EOF=-1,对EOF取非,就是对-1取非
[是位运算,它是将数据在内存中的每一位(当然是二进制)取反。-1在内存中所有位全部为1,(-1)=0,即对-1取非就是0]
就会跳出循环。

poj 3250:
3250 牛的视野(单调栈)
2012年11月27日 13:38:37 Onlyan 阅读数:4636
一群高度不完全相同的牛从左到右站成一排,每头牛只能看见它右边的比它矮的牛的发型,若遇到一头高度大于或等于它的牛,则无法继续看到这头牛后面的其他牛。
给出这些牛的高度,要求每头牛可以看到的牛的数量的和。
输入:(1)n,n头牛,(2)n行,表示每头牛的高度;
输出:每头牛能看到的牛的数量之和。
思路:
总思路:依次对每一头牛,计算有多少牛能看到它,加总;
1、一般算法:
(1)牛不能往左看,也就是,要把所有的高度都输入之后,再从最后一头开始,统计它前面有多少牛能看到它;
(2)注意,看到它与比它高不是同一个概念,比如对牛i,如果中间出现一个波动,在波峰左边的牛尽管比i高,但它也看不到i,被波峰挡住了。这个问题就比较麻烦,要找能看到i的,依次向前找到第一个比它高的比如j,再从j往前找比j高的k,则j、k都能看到i,而j、k之间比i高的则不能,这就意味着,找到k后,再去找比k高的第一个…每次计数。这个方法也是可以做出来的。
伪代码:
从i=n-1到0依次
{
tmp = num[i]; 用tmp来存放那个依次往前找到的牛,用于做下一次的比较;
从j=i-1 到0
{

  如果num[j] > tmp,则tmp = num[j];且 计数器sum++;  

//这样就保证每次找到的都是能看到的;
}
}
2、用单调栈:
(1)首先把要求作一下转换,求每头牛能看到的牛数量之和,其实就是求每头牛被看到的次数之和。这时一个问题的两个方面,但做这个转换之后,就不用等所有数都输入后再处理,而是变成每输入一头牛,统计前面有多少头牛能看到它。
(2)每输入一头牛时,就把栈里比它相等或矮的都弹出,于是剩下的就是比它高(能看到它的),把这个数量累加,然后再把这头牛压入栈;
(3)由于在压入栈时,已经把比它相等或矮的清除出去了,所以,就避免了前面波峰波谷的问题。
(4)基本步骤:
输入第一头牛高度,压入栈;
依次输入第2到n头牛,每输入一头时,(1)将栈里比它相等或矮的全弹出;(2)剩下的就是能看到它的,把栈中元素数量累加;(3)把当前牛压入栈;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值