【数据结构 | PTA】栈

7-1 汉诺塔的非递归实现

借助堆栈以非递归(循环)方式求解汉诺塔的问题(n, a, b, c),即将N个盘子从起始柱(标记为“a”)通过借助柱(标记为“b”)移动到目标柱(标记为“c”),并保证每个移动符合汉诺塔问题的要求。

输入格式:
输入为一个正整数N,即起始柱上的盘数。

输出格式:
每个操作(移动)占一行,按柱1 -> 柱2的格式输出。

输入样例:

3

输出样例:

a -> c
a -> b
c -> b
a -> c
b -> a
b -> c
a -> c
#include"stdio.h"
#include"stdlib.h"
int main()
{
	int N;
	scanf("%d",&N);
	int zhu[4][N+1];
	zhu[3][0]=0;
	zhu[1][0]=0;
	zhu[2][0]=0;
	char biaohao[5]=" abc";
	//puts(biaohao); 
	for(int aa=N;aa>0;aa--)//给源柱子加上盘子 
	{
		zhu[1][0]+=1;
		zhu[0][zhu[1][0]]=1;//记录所有盘子都在第一行 
		zhu[1][zhu[1][0]]=aa;
		//printf("%d",zhu[1][zhu[1][0]]);
	}
	int sum=0;//左移还是右移
	if(N%2==0)
	sum=1;
	else
	sum=-1;
	int start=1;
	int next=start+sum;//将移动到的柱子号
	int dang=1;//当前所移动的盘子号 
	int flag=-1;//当前盘子是否移动成功,0为否,1为真 
	int Z=0;//需要的总步数 
	while(zhu[3][0]!=N)
	{
		flag=-1;
		if(next>3)
		next=1;
		if(next<1)
		next=3;
		if(zhu[next][0]==0||zhu[start][zhu[start][0]]<zhu[next][zhu[next][0]])
		{
			zhu[next][0]+=1;
			zhu[next][zhu[next][0]]=zhu[start][zhu[start][0]];
			//盘子向右移动 
			zhu[0][zhu[next][zhu[next][0]]]=next;
			//更新刚刚所移动的盘子所在的柱子号 
			zhu[start][0]-=1;
			printf("%c -> %c\n",biaohao[start],biaohao[next]);
			flag=1; 
		}
		if(flag==1||next==start)
		//前者为移动成功,后者为移动失败
		{
			dang+=1;
			if(dang==N+1)
			dang=1;
			while(dang!=zhu[zhu[0][dang]][zhu[zhu[0][dang]][0]])
			//当前所要移动的盘子不在其柱子的顶层时进入循环 
			{
				dang+=1;
				if(dang==N+1)
			    dang=1;
			}
			start=zhu[0][dang];//更新将移动的盘子所在的柱子号
			next=start+sum; 
			}
		else
		next+=sum;		        
		}
}

7-2 出栈序列的合法性

给定一个最大容量为 m 的堆栈,将 n 个数字按 1, 2, 3, …, n 的顺序入栈,允许按任何顺序出栈,则哪些数字序列是不可能得到的?例如给定 m=5、n=7,则我们有可能得到{ 1, 2, 3, 4, 5, 6, 7 },但不可能得到{ 3, 2, 1, 7, 5, 6, 4 }。

输入格式:
输入第一行给出 3 个不超过 1000 的正整数:m(堆栈最大容量)、n(入栈元素个数)、k(待检查的出栈序列个数)。最后 k 行,每行给出 n 个数字的出栈序列。所有同行数字以空格间隔。

输出格式:
对每一行出栈序列,如果其的确是有可能得到的合法序列,就在一行中输出YES,否则输出NO

输入样例:

5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2

输出样例:

YES
NO
NO
YES
NO
#include<stack>
#include<queue>
#include<iostream>
#include<cstdio>
using namespace std;
int main() {
	stack<int>s;
	int m, n, k,flag;
	int arr[1000];
	cin >> m >> n >> k;
	for (int i = 0; i < k; i++) {
		for (int j = 0; j < n; j++) {
			cin >> arr[j];
		}
		int flag = 0;
		while (!s.empty()) {
			s.pop();
		}
		for (int i = 1; i <= n; i++) {
			if (s.size() < m) {
				s.push(i);
			}
			if (s.size() == m && s.top() != arr[flag]) {
				break;
			}
			while (!s.empty() && s.top() == arr[flag]) {
				s.pop();
				flag++;
			}
		}
		if (flag == n) cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}
}

7-3 简单计算器

本题要求你为初学数据结构的小伙伴设计一款简单的利用堆栈执行的计算器。如上图所示,计算器由两个堆栈组成,一个堆栈 S1 存放数字,另一个堆栈 S2 存放运算符。计算器的最下方有一个等号键,每次按下这个键,计算器就执行以下操作:

  1. 从 S1 中弹出两个数字,顺序为 n1 和 n2;
  2. 从 S2 中弹出一个运算符 op;
  3. 执行计算 n2 op n1;
  4. 将得到的结果压回 S1。

直到两个堆栈都为空时,计算结束,最后的结果将显示在屏幕上。

输入格式:
输入首先在第一行给出正整数 N(1<N≤103),为 S1 中数字的个数。
第二行给出 N 个绝对值不超过 100 的整数;第三行给出 N−1 个运算符 —— 这里仅考虑 +-*/ 这四种运算。一行中的数字和符号都以空格分隔。

输出格式:
将输入的数字和运算符按给定顺序分别压入堆栈 S1 和 S2,将执行计算的最后结果输出。注意所有的计算都只取结果的整数部分。题目保证计算的中间和最后结果的绝对值都不超过 109。

如果执行除法时出现分母为零的非法操作,则在一行中输出:ERROR: X/0,其中 X 是当时的分子。然后结束程序。

输入样例 1:

5
40 5 8 3 2
/ * - +

输出样例 1:

2

输入样例 2:

5
2 5 8 4 4
* / - +

输出样例 2:

ERROR: 5/0
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
stack<ll> s1;
stack<char> s2;
int main()
{
	ll n,a;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a;
		s1.push(a);
	}
	for(int i=1;i<n;i++)
	{
		char s;
		cin>>s;
		s2.push(s);
	}
	ll f=0,ff,num=0;
	for(int i=1;i<n;i++)
	{
		ll n1,n2,ans;
		char op;
		n1=s1.top();
		s1.pop();
		n2=s1.top();
		s1.pop();
		op=s2.top();
		s2.pop();
		if(op=='/'&&n1==0)
		{
			f=1;
			ff=n2;
			break;
		}
		if(op=='+') 
			ans=n2+n1;
		if(op=='-') 
			ans=n2-n1;
		if(op=='*') 
			ans=n2*n1;
		if(op=='/') 
			ans=n2/n1;
		num=ans;
		s1.push(ans);
	}
	if(f==1) cout<<"ERROR: "<<ff<<"/0"<<endl;
	else cout<<num<<endl;
	return 0;
 } 

7-4 盲盒包装流水线

众所周知,PAT 有 9 枚徽章,分别对应青铜、白银、黄金、白金、钻石、大师、王者、大圣、天神这 9 个段位,只有成绩非常优秀的考生才有资格获得刻有自己名字的徽章。现在,PAT 制作了徽章的小型纪念版,要制成盲盒给大家玩了!

下图是一条盲盒包装流水线的示意图。首先徽章通过进货口被压入货栈里,空盒在履带上从左向右传送。每次从货栈里弹出一枚徽章,进入打包机,装入一只空盒,打包后继续向右边传送。当货栈为空时,打包机会暂停,等待下一批徽章压入货栈。

lsx.png

每只盒子都有一个编号,小拼姐姐手里有进入流水线的空盒编号顺序表,也有每一批送往货栈的徽章顺序表,这样她其实可以知道每只盒子里装了哪种徽章。有些小朋友收到了盲盒,就想在拆封前问无所不知的小拼姐姐,盒子里的徽章是哪一种。但是因为盲盒总量有 105 这么多,小拼姐姐可记不住每只盒子里装的是什么,于是你就被请来写个程序帮小拼姐姐回复这种信息。

输入格式:

输入第一行给出 2 个正整数,分别为盲盒总量 N(≤105)和货栈容量 S(≤100)。接下来一行给出 N 只盒子的编号,编号由 5 位数字组成,给出的顺序是空盒进入传送带的顺序。随后 N/S(保证是整数)行,每行给出一批 S 枚徽章的类型,为 1-9 的数字,给出的顺序是从进货口入栈的顺序。

再下面给出一个正整数 K(≤104),为查询次数。随后 K 行,每行给出一个 5 位编号。

输出格式:

对每个查询编号,在一行中输出该盒子中装的徽章类型。如果编号是错误的,则在一行中输出 Wrong Number

输入样例:

10 5
00132 10093 92001 23333 66666 88888 09009 34658 82750 69251
1 2 3 4 5
9 8 7 6 1
5
66666
88888
69251
55555
10093

输出样例:

1
1
9
Wrong Number
4
#include <iostream>
#include <map>
#include <queue>
#include <stack>
using namespace std;
 
int main()
{
    map<int, int> res; //<盲盒编号,徽章类型>
    queue<int> emptybox; //空盒传送带
    queue<int> input; //徽章从进货口入栈的顺序
    stack<int> box; //货栈
 
    int n, s, temp; cin >> n >> s;
    for (int i = 0; i < n; i++) { //记录
        cin >> temp; emptybox.push(temp);
    }
    for (int i = 0; i < n; i++) {
        cin >> temp; input.push(temp);
    }
 
    while (!emptybox.empty()) { //打包
        for (int i = 0; i < s; i++) { //前s个徽章入栈
            box.push(input.front()); input.pop();
        }
        for (int i = 0; i < s; i++) {
            res.insert(make_pair(emptybox.front(), box.top()));
            emptybox.pop(); box.pop();
        }
    }
 
    int k; cin >> k;
    while (k--) { //判断
        cin >> temp;
        if (res.find(temp) != res.end())
            cout << res[temp] << endl;
        else
            cout << "Wrong Number" << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋说

感谢打赏,祝你平安喜乐。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值