1. 程式人生 > 其它 >基礎資料結構3.1——堆疊

基礎資料結構3.1——堆疊

題目上添加了超連結,大家點一下題目就會自動跳轉到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");
    }
}