#include <iostream>
using namespace std;
#include<stack>
#include<vector>
//栈与递归
/*栈的操作 stack
只能在栈顶插入或删除
push() 入栈 无返回值
pop() 出栈 无返回值
top() 取栈顶元素 返回T类型
empty() 栈为空 bool类型 true为空
size() 统计元素个数 非负整数(size_t类型)
*/
//手动实现栈 (简陋版)
struct Stack {
int data[10000];
int top = -1; //指向栈顶元素
void push(int x) {
top++;
if(top < 10000) {
data[top] = x;
} else {
top--;
cout<<"stack overflow "<<endl; //栈溢出
}
}
void pop() {
if(top >= 0) {
top--;
}
}
int topval() { //栈为空也要有返回值
if(top >= 0) {
return data[top];
} else {
return -1;
}
}
};
void test_01() {
Stack s;
for(int i = 1; i <= 10; i++) {
s.push(i);
}
for(int i = 1; i <= 10; i++) {
cout<< s.topval() <<" "; //无法持续遍历 ,只能边取出变查看 top -- pop
s.pop();
}
return;
}
/*应用
①火车出入站 分车厢 (栈的入栈元素 的出栈顺序 是否符合规则)
②括号匹配
*/
/*火车出入站 栈的元素顺序 合法性检测
栈s 按 1 -- n 顺序入栈
判断出栈顺序是否可以为 排列a
a元素个数
排列a
输入:
5
1 3 2 5 4
输出:
legal
----------
输入:
5
1 5 3 2 4
输出:
illegal
*/
void test_02() {
int n;
cin >> n;
vector<int> a(n); //初始长度n ,默认值0
for(int i = 0; i < n; i++) {
cin >> a[i];
}
stack<int> s;
int cur = 1; //当前
bool f = 1; //判断标记,1为合法
for(int i = 0; i < n; i++) {
while((s.empty() || s.top() != a[i] && cur <= n)) {//栈空时停止循环 ,当前大于n时,退出循环
s.push(cur); //按 1 -- n顺序入栈 (等于a[i]即找到元素时,出栈 进行判断)
cur++;
}
if(s.empty() || s.top() != a[i] ) { //栈为空时还未找完a[i]序列则不合法:
f = 0; //(全部出栈都找不到,说明在之前的判断中元素出栈了,即序列不合法)
break;
} else {
s.pop(); //遍历出栈 直到找到栈顶元素
}
}
if(f) {
cout<< "legal" <<endl;
} else {
cout<< "illegal" <<endl;
}
return;
}
/*递归
n! = n * (n-1)!
例子 3!
int factorial(1){
return 1;
}
int factorial(2){
return 2*factorial(1);
}
int factorial(3){
return 3*factorial(2); // 3 * 2*factorial(1) == 3 * 2 * 1
}
递归深度 -- 从最后执行的出口开始返回
递归易超时!
*/
int factorial(int n) {
if(n == 1) { //边界条件
return 1;
}
return n*factorial(n - 1);
}
int Fix(int n) {
if(n == 1 || n == 2) { //出口
return 1;
}
return Fix(n - 1) + Fix(n - 2);
}
/*实现 f(x) 函数 (-1e5 <= x <= 1e5)
0 x <= 0
1 x = 1
3*f(x/2) - 1 x > 1 && x % 2 ==0
3*f((x+1)/2) - 1 x > 1 && x % 2 ==1
*/
long long f_3(int x) { //蓝桥杯 long long 输出格式建议 %I64d
if(x <= 0) {
return 0; //分四段
}
if(x == 1) {
return 1;
}
if(x > 1 && x % 2 == 0) {
return 3 * f_3(x/2) - 1;
}
if(x > 1 && x % 2 == 1) {
return 3*f_3((x+1)/2) - 1;
}
}
void test_03() {
int x;
scanf("%d",&x);
printf("%I64d",f_3(x)); // !!!!!!
}
/*汉诺塔 栈结构
A B C
分三步:
1. n - 1 个盘子 从 A 到 B ,剩下最后一个盘子
2. A的最后一个盘子直接 A 到 C
3. 再把 n-1 个盘子 B 到 C
归为两种操作:
1.把多个盘子从一个柱子移动到另一个柱子,移第三个柱子为中介
2.把一个盘子从一个柱子_直接_移动到另一个柱子
*/
stack<int> S[3]; //二维 3柱子 每个柱子上 多个盘
void move(int x,int y) { //2.把一个盘子从一个柱子_直接_移动到另一个柱子
int temp = S[x].top(); //temp 移动的盘子
S[x].pop(); //x 柱子1
S[y].push(temp); //y 柱子2
cout << x << "-->" << y <<endl;
}
void hanio(int A,int B,int C,int n) { //1.把多个盘子从一个柱子移动到另一个柱子,移第三个柱子为中介
if(n == 1) {
move(A,C);
return;
}
//一次完整的移动
hanio(A,C,B,n - 1); // A -- >C , B辅助 ,移动盘子的数量
move(A,C); //最后一个剩余盘子 A --> C
hanio(B,A,C,n - 1); // B --> A , C辅助 ,移动盘子的数量
}
void test_04() {
int n;
cin >> n;
for(int i = n; i >= 1; i--) {
S[0].push(i);
}
hanio(0,1,2,n); //分别代表A、B、C ,初始移动 n个盘子
while(!S[2].empty()) { //输出移动后 C柱上的盘子
cout << S[2].top() << " "; //需控制行号空格
S[2].pop();
}
}
/*(写的函数已经最少次数 但递归时间超时 2 ^64)
求最小移动次数 和消耗体力(移动到第i号圆盘耗费i点体力)
f[n] = f[n - 1] + 1 + f[n - 1] //每一步移动盘子的三步走 移动次数
g[n] = g[n - 1] + n + g[n - 1] //每一步移动盘子的三步走 消耗体力
推导 次数 == 2^n - 1 别用pow(2,n) //大数会不准确
输入 盘子数量
输出 次数 体力
样例输入:
3
输出:
7 11
*/
long long f[65],g[65]; // (1<=n<=60) 数值可能到达 2 ^ 60
void test_05() {
int n;
scanf("%d",&n);
f[1] = 1;
for(int i = 2; i <= n; i++) {
f[i] = 2* f[i - 1] + 1; //推导次数公式
}
g[1] = 1;
for(int i = 2; i <= n; i++) {
g[i] = 2 * g[i - 1] + i; //记录到 i次时,总消耗体力
}
printf("%I64d %I64d\n",f[n],g[n]);
}
/*猴子吃桃
每天吃一半还多一个 == x/2 + 1
到第n天,剩下一个桃子 ,问开始共有多少个桃子
*/
int n_6;
int f_6(int x) {
if(x == n_6) {
return 1;
} else {
return (f_6(x + 1) + 1) * 2;
}
}
void test_06() {
scanf("%d",&n_6);
printf("%d",f_6(1));
}
/*斐波那契数列 变式
f(1) = f(2) = 1;
f(n) = a*f(n - 1) + b * f(n - 2)
输入 n ∈[1,100] , a∈[1,10] , b∈[1,10] ,p∈[1,2000]
输出f(n)对p取模的值
样例输入:
3 1 1 1000
输出:
2
*/
int ans_07[2005];
bool vis_07[2005];
int f_07(int n,int a,int b,int p) {
if(vis_07[n]) {
return ans_07[n];
}
vis_07[n] = true;
if(n == 1 || n == 2) {
return ans_07[n] = 1 % p; //等效返回ans[n]
} else {
return ans_07[n] = (a * f_07(n - 1,a,b,p) % p + b * f_07(n - 2,a,b,p) % p )%p; //依照题目 % p每次取模防止溢出
}
}
void test_07() {
int n,a,b,p;
scanf("%d%d%d%d",&n,&a,&b,&p);
printf("%d\n",f_07(n,a,b,p));
}
/*计算 x^y (主要是时间复杂度)
题目给出了快速幂的写法:(快速幂 :每次返回的结果再平方 到达ans循环次数减少)
| f(x,y/2) * f(x,y/2) y % 2 == 0
f(x,y) = | 1 y == 0
| f(x,y/2) * f(x,y/2) * x y % 2 == 1
输入格式:
第一行 整数t ∈[0,100]
接下来t行,每行有三个整数
x(1<= x <= 1e9) y(1<= y <= 1e18) p(1<= p <= le9)
输出 x^y%p 的值
样例输入:
1
2 10 10000
输出:
1024
*/
long long f_08(long long x,long long y,long long p) { //p位是不变的
if( y == 0) {
return 1 % p; //如果p=1 ,则为0 ,可能有坑,要加%p
} else if(y % 2 == 0) {
long long temp = f_08(x,y/2,p);
return temp * temp % p;
} else {
long long temp = f_08(x,y/2,p);
return temp * temp % p * x % p; //不断 %p 防止溢出
}
}
void test_08() {
int t;
scanf("%d",&t);
long long x,y,p;
while(t--) {
scanf("%I64d%I64d%I64d",&x,&y,&p);
printf("%I64d\n",f_08(x,y,p));
}
}
/*
第一行输入一个n代表一共有n个弹簧板 n∈[1,200] ,每个板占一个单位距离
第二行输入n个数字,中间用空格隔开
第i个数字 让 a[i] ∈[0,30] 代表第i个板可以让小球移动的距离
第三行输入n个数字,中间用空格隔开
第i个数字b[i]∈[0,30],表示第i个弹簧板可以让小球移动的距离
输出一个数,表示小球被弹起的最小次数
输入:
5
2 2 3 1 4
1 2 3 4 1
输出:
2
*/
int a_09[205],b_09[205];
int ans_09[205];
bool vis_09[205];
int n_09;
int f_09(int x) {
if(x >= n_09) {
return ans_09[x];
}
if(vis_09[x]) {
return ans_09[x];
}
vis_09[x] = true;
return min(f_09(x + a_09[x]) , f_09(x + b_09[x])) + 1;
}
void test_09() {
scanf("%d",&n_09);
for(int i = 0; i < n_09; i++) {
scanf("%d",&a_09[i]);
}
for(int i = 0; i < n_09; i++) {
scanf("%d",&b_09[i]);
}
printf("%d\n",f_09(0));
}
/*最大公约数
输入t (t行)
接下来t行 每行x y 求每行的最大公约数
样例输入:
1
6 8
输出:
2
*/
int gcd(int x,int y) {
if(y == 0)
return x;
return gcd(y,x%y); //最简写 ,不要用条件运算符
/*
}else{
return gcd(y,x%y);
}
*/
}
void test_10() {
int t;
int x,y;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&x,&y);
printf("%d",gcd(x,y));
}
return;
}
/*括号匹配
一个串 只包含 '(' 和 ')'
一对匹配的括号 :'(' 必须在 ')' 之前 (匹配的括号不能交叉,只能嵌套)
判断是否匹配 并输出匹配的一对括号的位置 (从1开始)
样例输入:
(())
输出:
Yes
1 4
2 3
*/
#include<cstdio>
#include<stack>
#include<cstring> //strlen strcpy ...
char s_11[50005]; //括号字符串
stack<int> s_1; //左括号入栈 ,遇到右括号栈非空,(有左括号)出栈
int ans[50005]; // 记录位置
void test_11() {
int len;
bool f = true;
scanf("%s",s_11);
len = strlen(s_11);
for(int i = 0; i < len; i++) {
if(s_11[i] == '(') {
s_1.push(i + 1);
} else {
if(!s_1.empty() ) { //还有左括号
ans[i + 1] = s_1.top();
s_1.pop();
} else { //未匹配完,栈已经空了(左括号不够)== 右括号多了
f = false;
break;
}
}
}
if(!s_1.empty()) { //匹配完,栈内还有左括号,左括号多了
f = false;
}
if(!f) { //没有匹配成功
printf("No\n");
} else {
printf("Yes\n");
for(int i = 1; i <= len; i++) { //输出i位置括号对应的括号 (位置从1开始)
if(ans[i]) {
printf("%d %d\n",ans[i],i);
}
}
}
}
/*浏览器
三种操作 : 打开页面 回退 前进
打开页面 : 在地址栏中输入网址,并跳转到网址对应的对面
回退:回到上一次访问到的页面
前进:返回到上次回退的页面,如果上一次的操作是打开页面,那么将无法前进
头文件
#include<iostream>
#include<stack>
输入n行,表示操作次数
如果有VISIT,后面接着输入一个不含有空格和换行的网址(长度< 100)
表示在浏览器中输入的网址,如果是BACK , 表示回退,FORWARD 表示前进
输出格式
操作成功输出操作后的网址,否则输出Ignore
样例输入:
10
VISIT http://www.jisuanke.com/course/476
VISIT http://www.taobao.com/
BACK
BACK
FORWARD
FORWARD
BACK
VISIT http://www.jisuanke.com/course/429
FORWARD
BACK
输出:
http://www.jisuanke.com/course/476
http://www.taobao.com/
http://www.jisuanke.com/course/476
Ignore
http://www.taobao.com/
Ignore
http://www.jisuanke.com/course/476
http://www.jisuanke.com/course/429
Ignore
http://www.jisuanke.com/course/476
*/
#include<queue>
#include<string> //要输入完再输出就多一个queue q存放每轮结果存放每轮
queue<string> q;
string op,s; //op 操作 s为输入网址
stack<string> s1, s2; //s1输出当前网址 , s2 临时存放回退前的网址
void test_12() {
int n;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> op;
if(op == "VISIT") { //表示输入网址
cin >> s;
while(!s2.empty()) { //等效清空! (栈无clear) !!!!
s2.pop();
}
s1.push(s); //网址放入s1
} else if(op == "BACK") {
if(s1.size() <= 1) { //回退到 至少剩下一个首页 ,初始界面
cout<< "Ignore" <<endl;
// q.push("Ignore");
continue;
}
s2.push(s1.top()); //存回退前网址(下一次前进网址)
s1.pop(); //出栈
} else {//前进
if(s2.empty()) { //没有可以前进的网址
cout<< "Ignore" <<endl;
// q.push("Ignore");
continue;
}
s1.push(s2.top()); //取s2存放的 回退前网址
s2.pop(); //清 临时存放网址
}
cout<< s1.top() << endl; //没有被忽略就打印 (continue会跳过此步)
// q.push(s1.top());
}
/*
while(!q.empty()){
q.pop();
}
*/
}
int main() {
test_12();
return 0;
}
汉诺塔