题目上添加了超链接,大家点一下题目就会自动跳转到Poj原题界面~~ 冲鸭冲鸭ヾ(◍°∇°◍)ノ゙。
前言:
堆栈相较于其它数据结构的特点是先进后出,常见实现有顺序栈、链栈,做题时顺序栈就足以应对绝大部分题目。常见题型有模拟、单调栈(点我一下试试)....总体来说不难。
3.1.1 Web Navigation (1028)
题意:使用堆栈模拟Web浏览器的操作,根据不同指令输出对应的结果。
小笔记:按要求模拟即可,可以通过双栈,也可以自己实现一个可以访问中间变量的栈。
#include <iostream>
#include <string>
#include <stack>
using namespace std;
int main()
{
stack<string> F, B;
string URL = "http://www.acm.org/";
string C;
do
{
cin >> C;
switch (C[0])
{
case 'V':
B.push(URL);
while (!F.empty())
F.pop();
cin >> URL;
cout << URL << endl;
break;
case 'B':
if (B.empty())
cout << "Ignored" << endl;
else
{
F.push(URL);
URL = B.top();
B.pop();
cout << URL << endl;
}
break;
case 'F':
if (F.empty())
cout << "Ignored" << endl;
else
{
B.push(URL);
URL = F.top();
F.pop();
cout << URL << endl;
}
break;
}
} while (C[0] != 'Q');
return 0;
}
或者手动实现栈
#include <iostream>
#include <string>
using namespace std;
string web[105]; //自己动手,实现可以访问栈中位置元素的栈,从而避免双栈
int main()
{
web[0] = "http://www.acm.org/";
string s, tmp;
int i = 0; //记录指针
while (cin >> s)
{
if (s == "QUIT")
break;
if (s == "VISIT")
{
string ch;
cin >> ch;
web[++i] = ch;
tmp = ch; //记录最新入栈web
cout << ch << endl;
}
if (s == "BACK")
{
i--;
if (i <= -1) //注意下标越界问题
i = -1, cout << "Ignored" << endl;
else
cout << web[i] << endl;
}
if (s == "FORWARD")
{
if (tmp == web[i])
cout << "Ignored" << endl;
else
{
if (i < 0)
i = 0;
cout << web[++i] << endl; //第一个页面不可能是前进得来,所以此处为++i
}
}
}
return 0;
}
3.1.2 Bad Hair Day (3250)
题意:n头牛站成一排,每头牛高度分别为h,从左边第1头牛向右看,到下一个比它高的牛之前,之间比它低的牛的数目计为c,计算这n头牛的c值的和。
小笔记:经典单调栈问题,简单题
#include <cstdio>
#include <stack>
using namespace std;
int main()
{
int n;
long long ans = 0;
stack<long long> c;
scanf("%d", &n);
while (n--)
{
int h;
scanf("%d", &h);
while (!c.empty() && h >= c.top())
c.pop();
ans += c.size();
c.push(h);
}
printf("%lld
", ans);
return 0;
}
3.1.3 Rails (1363)
题意:判断一个队列是否能用另一个队列通过入栈出栈操作形成。
小笔记:依次入栈比对即可。简单题
#include <cstdio>
#include <stack>
using namespace std;
bool solve(int n)
{
int a = 1;
bool p = true; //判断是否能够成功输出B
stack<int> S;
while (n--)
{
int b; //B序列中的数字
scanf("%d", &b);
if (!b)
return false;
while (a <= b)
S.push(a++);
if (!S.empty() && S.top() == b)
S.pop();
else
p = false;
}
printf(p ? "Yes
" : "No
");
return true;
}
int main()
{
int n;
while (scanf("%d", &n) && n)
{
while (solve(n))
;
printf("
");
}
return 0;
}
3.1.4 Terrible Sets (2082)
题意:依次给出n个矩形的长和高,这些矩形分布在第一象限,底边在x轴并列排放,求由这些矩形覆盖的区域所组成的最大矩形的面积。
小笔记:单调栈例题,题解链接给大家了,非常建议去听一下。
#include <cstdio>
#include <stack>
using namespace std;
struct Rectangle
{
int w;
int h;
};
int W; //记录扫描到的宽度w的和
int ans; //最大面积
stack<Rectangle> s;
//用新加入的矩形的高h对栈中元素进行扫描
void scan(int h)
{
W = 0;
while (!s.empty() && s.top().h > h)
{
W += s.top().w;
ans = max(ans, W * s.top().h);
s.pop();
}
}
int main()
{
int n;
while (scanf("%d", &n) && ~n)
{
ans = 0;
int H = 0; //记录最后入栈的矩形的高度h
while (n--)
{
Rectangle r;
scanf("%d%d", &r.w, &r.h);
if (r.h < H)
{
scan(r.h);
W += r.w;
r.w = W;
}
s.push(r);
H = r.h;
}
scan(0); //所有矩阵处理完之后还需要再扫描一遍
printf("%d
", ans);
}
return 0;
}
3.1.5 Code (1780)
题意:设计软件来破译n位的数字密码,生成一个长度为10n+n-1的数字序列,只要序列中出现正确密码,即可破译,数字序列应该包含所有组合,输出这个序列(字典序最小)。
小笔记:啊,这道题看起来太痛苦了...十分劝退,是个欧拉回路(一笔画)问题。挺难的,应该可以算省赛金牌题了。
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1000010;
const int P[] = {1, 10, 100, 1000, 10000, 100000, 1000000};
int S[N]; //自定义堆栈
int p[N]; //记录序列下一位的值
bool v[N]; //记录该点是否被访问
int main()
{
int n;
while (scanf("%d", &n) && n)
{
int m = P[n];
fill(v, v + m, false);
fill(p, p + m, 0);
int top = 0;
S[top] = 0;
v[0] = true;
while (top < m - 1)
{
int i = S[top];
if (p[i] == 10)
{
top--;
v[i] = false;
p[i] = 0;
continue;
}
p[i]++;
int j = (i * 10 + p[i] - 1) % m;
if (!v[j])
{
S[++top] = j;
v[j] = true;
}
}
for (int i = 1; i < n; i++)
putchar('0');
for (int i = 0; i < m; i++)
putchar(S[i] % 10 + '0');
printf("
");
}
}