栈和队列例题

这篇博客介绍了两个算法问题,一是利用栈计算一系列矩形沿x轴排列的最大连续区域面积,二是模拟队伍排队过程,允许特定条件下插队。通过示例输入和输出解释了解题思路,并提供了C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、连续区域矩形面积(栈)

题目概述

Sample Input

3
1 2
3 4
1 2
3
3 4
1 2
3 4
-1

Sample Output12
14

题目大意:给出一系列矩形的宽度和高度,矩形沿着x轴对齐,求这些矩形组成的连续矩形区域的最大面积。
解题方法:这是一道非常好的题,用栈保存矩形,如果高度递增则不断入栈,如果遇到当前输入的比栈顶高度小,则从栈顶开始不断出栈并且计算最大面积,直到栈顶高度小于当前输入高度则停止出栈,并把开始出栈矩形的宽度累加得到totalw,把totalw和当前输入的矩形宽度相加得到当前输入矩形的宽度,并入栈,这样栈中保存的永远都是高度递增的矩形,最后输入完了之后如果栈不为空,则依次出栈并计算最大面积。(ACM题目原型(POJ2082))
#include <bits/stdc++.h>
using namespace std;
int n,maxS=0;
typedef struct{
	int w,h;
}rec;
int main() {
	stack<rec> s;
	while(scanf("%d", &n) != EOF && n != -1)
	{
		int w,h,totalW;
		maxS=0; 
		for(int i=0;i<n;i++)
		{
			cin>>w>>h;
			if(s.empty())  //如果栈为空 表明第一次有矩形输入 直接入栈 
			{
				rec t;
				t.w=w;
				t.h=h;
				s.push(t); 
			}
			else  //栈里已经有值  判断决定出栈计算值 or 入栈 
			{
				totalW=0;
				//注意出栈后一定要判断空 不然程序可能会死循环 
				while(!s.empty()&&s.top().h>h)  //栈顶矩形的高度大于新矩形的高度  出栈 
				{
					totalW+=s.top().w;
					if(totalW*s.top().h>maxS)
						maxS=totalW*s.top().h;
					s.pop();
				}
				//执行下面的语句时两种情况: totalW已经更新过需要新矩形入栈 or  totalW仍然为0新矩形需要入栈
				totalW+=w;
				rec t;
				t.w=totalW;
				t.h=h;
				s.push(t); 
			} 
		}
		totalW=0;  //下面这种情况属于矩形的高度始终递增 则还没有计算过最大面积 需清除totalW 重新计算  
		while(!s.empty())
		{
			rec t=s.top();
			totalW+=t.w;
			if(t.h*totalW>maxS)
				maxS=t.h*totalW;
			s.pop();
		}
		cout<<maxS<<endl;
	}
	return 0;
}

二、模拟插队

题目概述:

Sample input

2
3 101 102 103
3 201 202 203
ENQUEUE 101
ENQUEUE 201
ENQUEUE 102
ENQUEUE 202
ENQUEUE 103
ENQUEUE 203
DEQUEUE
DEQUEUE
DEQUEUE
DEQUEUE
DEQUEUE
DEQUEUE
STOP
2
5 259001 259002 259003 259004 259005
6 260001 260002 260003 260004 260005 260006
ENQUEUE 259001
ENQUEUE 260001
ENQUEUE 259002
ENQUEUE 259003
ENQUEUE 259004
ENQUEUE 259005
DEQUEUE
DEQUEUE
ENQUEUE 260002
ENQUEUE 260003
DEQUEUE
DEQUEUE
DEQUEUE
DEQUEUE
STOP
0

Sample output

Scenario #1
101
102
103
201
202
203

Scenario #2
259001
259002
259003
259004
259005
260001

大概题意:类似于学校排队打饭,模拟这过程,只有队伍中有你们班的人你才可以插队,不然你只能排在队尾。ENQUEUE x,代表编号为x的人来排队,DEQUEUE时表明队伍最前面的人出队列,STOP时停止。

执行思路:详见代码,大概是,用一个队列数组来表明那个班的人员所有编号,一个队列来模拟当前的班级排队情况,牵涉到很多标记数组,如:用一个数组映射人员编号和队伍,一个数组标记在排队的班级号,剩下的直接模拟队列就好。(Uva 540 - Team Queue

 

#include <bits/stdc++.h>
using namespace std;
/*
需要申明的变量:
数组队列nQueue:用以存储每个队有哪些人
标记队列nS:标识在排队的队伍号
标记数组nFlag:标识在排队的队伍号 
标记数组nM:标记每一个队员的队号  如:nM[1001]=1 
*/ 
queue<long> nQueue[1001];  //最多每个队伍只有1001个人
queue<int> nS;
int nM[1000000],nCaseNum = 0,nNum; //人总数不超过1000000,nCaseNum为第几次模拟排队,nNum为本轮的队伍数 
bool nFlag[1001]; //每个队伍是否在队列中的标志
 
void initQueue();
void queueInput();
void queueStimulate(); 
int main() {
	while(scanf("%d",&nNum)!=EOF&&nNum!=0)
	{
		initQueue();
		queueInput();
		queueStimulate();
	}
}

void initQueue()
{
	for (int i = 0; i != nNum; ++i)
	{
		nFlag[i]=false;
		while(!nQueue[i].empty())  //每个队伍清空 
			nQueue[i].pop();
	}
	while(!nS.empty()) nS.pop();  //标志队列清空 
}
void queueInput()
{
	long nElem,elemNum;  //elemNum代表每个队伍的人数 nElem代表每个队伍的人的编号 
	for(int i=0;i!=nNum;++i)
	{
		cin>>elemNum;
		for(int j=0;j!=elemNum;++j)
		{
			cin>>nElem;
			nM[nElem]=i;  //记录每个人的队伍号 
		}
	}	
}
void queueStimulate()
{
	string nCommand;
	long nElem;
	cout << "Scenario #" << ++nCaseNum << endl;
	while(cin>>nCommand,nCommand!="STOP")
	{
		if(nCommand=="ENQUEUE")  //入队列 
		{
			cin>>nElem;
			if(!nFlag[nM[nElem]])  //表明队伍中不存在当前队伍
			{
				nFlag[nM[nElem]]=true;  //把相关标志位均置位 
				nS.push(nM[nElem]);
			}
			nQueue[nM[nElem]].push(nElem); //把这个人放进对应的队伍中 
		}
		else if(nCommand=="DEQUEUE")  //出队列 
		{
			int nID=nS.front();
			
			cout<<nQueue[nID].front()<<endl;  //输出在队首的人员编号并弹出 
			nQueue[nID].pop();
			//处理弹出操作后带来的标识位变化 
			if(nQueue[nID].empty())
			{
				nS.pop();
				nFlag[nID]=false;
			}
		}
	}
	cout<<endl;
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值