7-1 汉诺塔的非递归实现
分数 25
全屏浏览题目
切换布局
作者 DS课程组
单位 浙江大学
借助堆栈以非递归(循环)方式求解汉诺塔的问题(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<stack>
#include<iostream>
using namespace std;
char s[3] = { 'a', 'b', 'c' };
stack<int> a[3];
bool move(int before, int after)
{
if (a[before].empty())
return false;
if (!a[after].empty()){
if (a[after].top() - a[before].top() < 0)
return 0;
}
a[after].push(a[before].top());//依次将栈中栈顶元素移至中转栈
a[before].pop();
printf("%c -> %c\n", s[before], s[after]);
return true;
}
int main()
{
int N, count = 0;
cin >> N;
for (int i = 0; i < N; i++)
a[0].push(N - i);//初始化第一个栈,也就是a[N]放在栈底,a[0]在栈顶
if (N % 2 == 1)
{
s[1] = 'c';
s[2] = 'b';
}
while (++count){
move((count - 1) % 3, count % 3);
if (!move((count - 1) % 3, (count + 1) % 3))
if (!move((count + 1) % 3, (count - 1) % 3))
break;
}
return 0;
}
7-2 表达式转换
分数 25
全屏浏览题目
切换布局
作者 DS课程组
单位 浙江大学
算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。
输入格式:
输入在一行中给出不含空格的中缀表达式,可包含+
、-
、*
、/
以及左右括号()
,表达式不超过20个字符。
输出格式:
在一行中输出转换后的后缀表达式,要求不同对象(运算数、运算符号)之间以空格分隔,但结尾不得有多余空格。
输入样例:
2+3*(7-4)+8/4
输出样例:
2 3 7 4 - * + 8 4 / +
#include <stdio.h>
#include <string.h>
char stack[50], str[50], post[50]; // 符号栈,表达式字符串,输出栈
int top1 = -1, top2 = -1;
char Pop( char c )
{
if (c == 'D') return '/';
if (c == 'C') return '*';
if (c == 'B') return '+';
if (c == 'A') return '-';
}
void Compare( char c ) // 传入字符来比较优先级进而对stack执行相应的操作
{
if (c == ')') // 如果遇到右括号
{
while (stack[top1] != '(' && top1 != -1) // 一直出栈直到遇到第一个左括号或栈空
{
post[++top2] = Pop(stack[top1]); // 弹出到输出栈
post[++top2] = ' ';
stack[top1--] = '\0'; // 栈顶下移
}
stack[top1--] = '\0'; // 此时stack[top1]为左括号,直接弹出即可
}
else // 如果是其他的操作符
{
while (stack[top1] >= c && stack[top1] != '(' && top1 != -1) // 一直出栈直到遇到优先级更小或者左括号或栈空
{
post[++top2] = Pop(stack[top1]); // 弹出到输出栈
post[++top2] = ' ';
stack[top1--] = '\0'; // 栈顶下移
}
stack[++top1] = c;
}
}
int main(void)
{
scanf("%s", str);
for (int i = 0; str[i] != '\0'; i++)
{
if (str[i] == '(')
stack[++top1] = str[i]; // 左括号直接入栈
else if (str[i] == '-' && (i == 0 || str[i - 1] == '(')) // 负号进入输出栈
post[++top2] = str[i];
else if (str[i] == '+' && (i == 0 || str[i - 1] == '(')) // 遇到正号直接跳过
continue;
else if (str[i] == '-' && i !=0 && str[i - 1] != '(') // 减号
Compare('A');
else if (str[i] == '+' && i != 0 && str[i - 1] != '(') // 加号
Compare('B');
else if (str[i] == '*') // 乘号
Compare('C');
else if (str[i] == '/') // 除号
Compare('D');
else if (str[i] == ')') // 右括号
Compare(')');
else
{ // 对待运算符外的字符,最好的方法是一视同仁,只在运算符上进行限制
post[++top2] = str[i];
if (str[i + 1] == '+' || str[i + 1] == '-' || str[i + 1] == '*'
|| str[i + 1] == '/' || str[i + 1] == '(' || str[i + 1] == ')' || str[i + 1] == '\0')
post[++top2] = ' '; // 输出一位空格
}
}
while (top1 != -1) // 栈中剩余运算符全部输出
{
post[++top2] = Pop(stack[top1--]);
post[++top2] = ' ';
}
if (post[top2] == ' ')
post[top2--] = '\0'; // 如果结尾是多余空格则删除掉
printf("%s", post);
return 0;
}
7-3 出栈序列的合法性
分数 25
全屏浏览题目
切换布局
作者 陈越
单位 浙江大学
给定一个最大容量为 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<iostream>
#include<bits/stdc++.h>
using namespace std;
int main()
{
int i, j;
int n,m,k;
cin>>m>>n>>k;
int a[k][n], s[k];
for(i = 0;i < k;i++)
{
for(j = 0;j < n;j++)
{
cin>>a[i][j];
}
}
for(i = 0;i < k;i++)
{
stack<int> st;
int bj = 0;
for(j = 1;j <= n;j++)
{
if(st.size() < m)
st.push(j);
else
break;//栈满
while(!st.empty())
{
if(st.top() != a[i][bj])
break;
else
{
st.pop();
bj++;
continue;
}
}
}
if(st.empty())
s[i] = 1;
else
s[i] = 0;
}
for(i = 0;i < k;i++)
if(s[i])
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
return 0;
}
7-4 包装机
分数 25
全屏浏览题目
切换布局
作者 陈越
单位 浙江大学
一种自动包装机的结构如图 1 所示。首先机器中有 N 条轨道,放置了一些物品。轨道下面有一个筐。当某条轨道的按钮被按下时,活塞向左推动,将轨道尽头的一件物品推落筐中。当 0 号按钮被按下时,机械手将抓取筐顶部的一件物品,放到流水线上。图 2 显示了顺序按下按钮 3、2、3、0、1、2、0 后包装机的状态。
图1 自动包装机的结构
图 2 顺序按下按钮 3、2、3、0、1、2、0 后包装机的状态
一种特殊情况是,因为筐的容量是有限的,当筐已经满了,但仍然有某条轨道的按钮被按下时,系统应强制启动 0 号键,先从筐里抓出一件物品,再将对应轨道的物品推落。此外,如果轨道已经空了,再按对应的按钮不会发生任何事;同样的,如果筐是空的,按 0 号按钮也不会发生任何事。
现给定一系列按钮操作,请你依次列出流水线上的物品。
输入格式:
输入第一行给出 3 个正整数 N(≤100)、M(≤1000)和 Smax(≤100),分别为轨道的条数(于是轨道从 1 到 N 编号)、每条轨道初始放置的物品数量、以及筐的最大容量。随后 N 行,每行给出 M 个英文大写字母,表示每条轨道的初始物品摆放。
最后一行给出一系列数字,顺序对应被按下的按钮编号,直到 −1 标志输入结束,这个数字不要处理。数字间以空格分隔。题目保证至少会取出一件物品放在流水线上。
输出格式:
在一行中顺序输出流水线上的物品,不得有任何空格。
输入样例:
3 4 4
GPLT
PATA
OMSA
3 2 3 0 1 2 0 2 2 0 -1
输出样例:
MATA
//L2-1 包装机
#include <iostream> vxgzh:xtsn
using namespace std;
#include <stack>
#define N 105
stack <char> sta;
string s[N];
int main()
{
int n,m,smax,i,x;
int pi[N]={0}; //记录每条轨道最左边物品的下标/位置
cin>>n>>m>>smax; //输入
char c;
cin.ignore(); //忽略上一次cin输入最后面的换行符
for(i=0;i<n;i++) //输入每条轨道的物品信息
cin>>s[i];
while(1)
{
cin>>x; //输入按下的按钮
if(x==-1)
break;
else if(x==0&&!sta.empty())
{
c=sta.top(); //从筐中抓出
cout<<c;sta.pop();
}
else if(x>0)
{
if(pi[x-1]<m)
{
if(sta.size()==smax) //框已满
{
c=sta.top(); //从筐中抓出
cout<<c;sta.pop();
}
c=s[x-1][pi[x-1]];pi[x-1]++;
sta.push(c); //推进筐
}
}
}
return 0;
}