基礎資料結構3.1——堆疊
阿新 • • 發佈:2021-08-09
題目上添加了超連結,大家點一下題目就會自動跳轉到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\n", 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\n" : "No\n"); return true; } int main() { int n; while (scanf("%d", &n) && n) { while (solve(n)) ; printf("\n"); } 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\n", 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("\n"); } }