吐血整理 PTA 團體程序設計天梯賽題解

去年參加了一次天梯賽,畢竟才大一,水平有限,L1 基本答了,L2 混了幾題部分正確,L3 題目還沒點開過。今年再戰,順便更新更新題解,也做本身複習用。另外,日常 HDU 的題目作多了,養成了動不動就用 scanfprintf 的習慣,其實 PTA 的題基本上用 cincout 都能過的,因此 下面的代碼中的全部 c 語言部分爲了方便,均可以換成 c++,畢竟 scanfprintf 不只字母多,裏面還要打一堆 % 太繁瑣了。

題解在不按期更新中,水平有限,最多也就作到 L2,歡迎在評論中提出問題,一塊兒討論。node

2020-01-09 更新: L1-015 ~ L1-017
2020-01-15 更新: L1-018 ~ L1-020
2020-01-20 更新: L2-002, L2-003

刷題連接 👉ios

關於 bits/stdc++.h

一個「萬能頭文件」,基本上經常使用的 STL 都在裏面了,ACM 比賽就是怎麼高效怎麼來,這麼好用的東西不用白不用。c++

L1 部分題解

因爲 L1 題目廣泛簡單,因此備註比較少,後面的 L2 題目會適當加上備註。算法

L1-001 Hello World (5 分)

pta 最難的一題!!!數組

#include <bits/stdc++.h>
using namespace std;
int main() {
    cout << "Hello World!";
    return 0;
}

L1-002 打印沙漏 (20 分)

由於圖形上下對稱,因此能夠先計算出上半圖形的高度、寬度,這題主要就是考察邏輯思惟。數據結構

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, height = 1, width = 1;
    char ch;
    cin >> n >> ch;
    --n;  // 先扣去最中間的一個字符
    while (true) {
        if (n - 2 * (width + 2) >= 0) {
            ++height;
            width += 2;
            n -= 2 * width;
        } else
            break;
    }
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < i; ++j) cout << ' ';
        for (int j = 0; j < 2 * height - 1 - 2 * i; ++j) cout << ch;
        cout << '\n';
    }
    for (int i = 0; i < height - 1; ++i) {
        for (int j = 0; j < height - 2 - i; ++j) cout << ' ';
        for (int j = 0; j < 2 * (i + 1) + 1; ++j) cout << ch;
        cout << '\n';
    }
    cout << n;
    return 0;
}

L1-003 個位數統計 (15 分)

雖然題目描述須要輸入正整數,可是輸入正整數須要一次一次取模才能獲得各位,直接以字符串的方式輸入就很簡單。post

#include <bits/stdc++.h>

using namespace std;

int main() {
    int cnt[10] = {0};
    string num;
    cin >> num;
    for (int i = 0; i < num.size(); ++i) ++cnt[num[i] - '0'];
    for (int i = 0; i < 10; ++i)
        if (cnt[i] > 0) cout << i << ':' << cnt[i] << '\n';
    return 0;
}

L1-004 計算攝氏溫度 (5 分)

沒有什麼難點,L1 不少題都像這樣。測試

#include <bits/stdc++.h>

using namespace std;

int main() {
    int F;
    cin >> F;
    int C = 5 * (F - 32) / 9;
    cout << "Celsius = " << C;
    return 0;
}

L1-005 考試座位號 (15 分)

把試機座位號看成下標,而後准考證號和考試座位號分別存入 a, b 數組,最後輸出就好。(准考證號 16 位,int 裝不下)優化

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
LL x, a[1005];
int n, m, y, z, b[1005];

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
        scanf("%lld%d%d", &x, &y, &z);
        a[y] = x;
        b[y] = z;
    }
    scanf("%d", &m);
    for (int i = 0; i < m; ++i) {
        scanf("%d", &y);
        printf("%lld %d\n", a[y], b[y]);
    }
    return 0;
}

L1-006 連續因子 (20 分)

用循環模擬出可能的連續因子序列。須要注意幾個優化的地方,for (int i = 2; i <= sqrt(n); ++i),很好理解,大於 sqrt(n) 的數再隨便乘一下就大於 n 了,確定就不是因子,因此這裏只走到 sqrt(n)ui

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
LL n, tmp;
int start, len;

int main() {
    scanf("%lld", &n);
    for (int i = 2; i <= sqrt(n); ++i) {
        tmp = 1;
        for (int j = i; tmp * j <= n; ++j) {
            tmp *= j;
            if (n % tmp) break;  // 若是tmp不是n的因子,再乘任何數也不是
            if (j - i + 1 > len) {
                start = i;
                len = j - i + 1;
            }
        }
    }
    if (!start) {
        start = n;
        len = 1;
    }
    printf("%d\n%d", len, start);
    for (int i = 1; i < len; ++i) printf("*%d", start + i);
    return 0;
}

L1-007 念數字 (10 分)

只要注意行尾不能有空格就行了。

#include <bits/stdc++.h>

using namespace std;

string a[] = {"ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu"};

int main() {
    string s;
    cin >> s;
    if (s[0] == '-')
        cout << "fu";
    else
        cout << a[s[0] - '0'];
    for (int i = 1; i < s.size(); ++i)
        cout << ' ' << a[s[i] - '0'];
    return 0;
}

L1-008 求整數段和 (10 分)

只能說 pta 的題太細節了,不難的一題可是正確率很低,由於很容易出現恰好 5 個數時,最後連換兩行的狀況。

#include <bits/stdc++.h>

using namespace std;

int main() {
    int a, b, sum = 0;
    scanf("%d%d", &a, &b);
    for (int i = a; i <= b; ++i) {
        sum += i;
        printf("%5d", i);
        if ((i - a + 1) % 5 == 0)
            printf("\n");
        else if (i == b)
            printf("\n");
    }
    printf("Sum = %d", sum);
    return 0;
}

L1-009 N 個數求和 (20 分)

分數求和,難點就是通分,須要求最大公約數,能夠用歐幾里得算法(gcd)求得。最後還有一點須要注意,測試數據是在長整型範圍內的。

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;

LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); }

int main() {
    char c;
    int n;
    LL x, y, tmp;
    cin >> n;
    cin >> x >> c >> y;
    LL sx = x, sy = y;
    for (int i = 1; i < n; ++i) {
        cin >> x >> c >> y;
        tmp = sy / gcd(sy, y) * y;
        sx = sx * (tmp / sy) + x * (tmp / y);
        sy = tmp;
    }
    LL num = sx / sy;
    sx %= sy;
    tmp = gcd(sx, sy);
    sx /= tmp;
    sy /= tmp;
    if (sx == 0)
        cout << num;
    else if (num == 0)
        cout << sx << '/' << sy;
    else
        cout << abs(num) << ' ' << sx << '/' << sy;
    return 0;
}

L1-010 比較大小 (10 分)

簡單的排個序。

#include <bits/stdc++.h>

using namespace std;

int main() {
    int a[3];
    for (int i = 0; i < 3; ++i)
        cin >> a[i];
    sort(a, a + 3);
    cout << a[0] << "->" << a[1] << "->" << a[2];
    return 0;
}

L1-011 A-B (20 分)

字符串,查找,刪除。

#include <bits/stdc++.h>

using namespace std;

int main() {
    string a, b;
    getline(cin, a);
    getline(cin, b);
    for (int i = 0; i < b.size();) {
        if (a.find(b[i]) != -1)
            a.erase(a.find(b[i]), 1);
        else
            ++i;
    }
    cout << a;
    return 0;
}

L1-012 計算指數 (5 分)

水題。

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    cin >> n;
    cout << "2^" << n << " = " << pow(2, n);
    return 0;
}

L1-013 計算階乘和 (10 分)

水題。

#include <bits/stdc++.h>
using namespace std;

int fac(int x) { return x == 1 ? 1 : fac(x - 1) * x; }

int main() {
    int n, sum = 0;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        sum += fac(i);
    cout << sum;
    return 0;
}

L1-014 簡單題 (5 分)

水題三連。

#include <iostream>
using namespace std;
int main() {
    cout << "This is a simple problem.";
    return 0;
}

L1-015 跟奧巴馬一塊兒畫方塊 (15 分)

主要就是四捨五入的部分,用二進制騷一下。

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    char c;
    cin >> n >> c;
    int m = (n & 1) ? n / 2 + 1 : n / 2;  // 四捨五入
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j)
            cout << c;
        cout << endl;
    }
    return 0;
}

L1-016 查驗身份證 (15 分)

水題,就是麻煩了點。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int a[] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    int b[] = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
    int n;
    cin >> n;
    string s;
    bool flag = false;
    while (n--) {
        int sum = 0;
        cin >> s;
        for (int i = 0; i < s.size() - 1; ++i)
            sum += (s[i] - '0') * a[i];
        sum %= 11;
        if (b[sum] != s.back()) {
            cout << s << endl;
            flag = true;
        }
    }
    if (!flag)
        cout << "All passed";
    return 0;
}

L1-017 到底有多二 (15 分)

cout << setiosflags(ios::fixed) << setprecision(2) 控制小數點位數。

#include <bits/stdc++.h>
using namespace std;

int main() {
    string s;
    cin >> s;
    int cnt = 0;
    double flag = 1;
    if (s[0] == '-') {
        flag *= 1.5;
        s.erase(s.begin(), s.begin() + 1);
    }
    if ((s.back() - '0') % 2 == 0) flag *= 2;
    for (int i = 0; i < s.size(); ++i)
        if (s[i] == '2') ++cnt;
    cout << setiosflags(ios::fixed) << setprecision(2)
         << cnt * flag / s.size() * 100 << '%';
    return 0;
}

L1-018 大笨鐘 (10 分)

注意 12 點整不須要敲,過了 12 點就要敲。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int h, m;
    scanf("%d:%d", &h, &m);
    if (h >= 0 && h < 12 || h == 12 && m == 0)
        printf("Only %02d:%02d.  Too early to Dang.", h, m);
    else {
        if (m == 0)
            h -= 12;
        else
            h -= 11;
        while (h--)
            printf("Dang");
    }
    return 0;
}

L1-019 誰先倒 (15 分)

這題比較坑,假如酒量給的是 1,須要喝 2 杯才能倒,因此輸入兩人的酒量後,都須要加 1。另外題目描述第二行輸入一個正整數 N,實際上 N 根本沒用。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, m, _, a, b, c, d;
    int cnt1 = 0, cnt2 = 0;
    cin >> n >> m >> _;
    ++n, ++m;
    while (n && m) {
        cin >> a >> b >> c >> d;
        int tmp = a + c;
        if (b == tmp && d != tmp) {
            --n;
            ++cnt1;
        } else if (b != tmp && d == tmp) {
            --m;
            ++cnt2;
        }
    }
    if (n)
        cout << "B\n" << cnt1;
    else
        cout << "A\n" << cnt2;
    return 0;
}

L1-020 帥到沒朋友 (20 分)

朋友圈人數若是爲 1,不作處理。大於 1 的話,說明有朋友,作個標記,注意輸出格式。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, k, id;
    vector<bool> fri(100000, false), vis(100000, false);
    cin >> n;
    while (n--) {
        cin >> k;
        if (k == 1)
            cin >> id;
        else {
            while (k--) {
                cin >> id;
                fri[id] = true;
            }
        }
    }
    cin >> n;
    bool flag = false;
    while (n--) {
        cin >> id;
        if (!fri[id] && !vis[id]) {
            if (flag) cout << ' ';
            cout << setfill('0') << setw(5) << id;
            vis[id] = flag = true;
        }
    }
    if (!flag) cout << "No one is handsome";
    return 0;
}

L1-059 敲笨鍾 (20 分)

就是幾個知識點,getline 前用 cin.get() 吸取回車,而後一些字符串基本操做,find 正向查找,rfind 反向查找,substr 切割。最後就是須要考慮到一種特殊狀況,逗號前的字符不足 3 個,那麼直接去使用 str.substr(p - 3, 3) == "ong" 判斷的話就會出現錯誤(最後一組測試數據),因此須要加上 p >= 3 這個前提條件。

#include <bits/stdc++.h>

using namespace std;

int main() {
    string str;
    int n;
    cin >> n;
    cin.get();
    while (n--) {
        getline(cin, str);
        int p = str.find(',');
        if (p >= 3 && str.substr(p - 3, 3) == "ong" &&
            str.substr(str.size() - 4, 3) == "ong") {
            p = str.size();
            for (int i = 0; i < 3; ++i) p = str.rfind(' ', p - 1);
            cout << str.substr(0, p) << " qiao ben zhong.\n";
        } else
            cout << "Skipped\n";
    }
    return 0;
}

L2 部分題解

[最短路] L2-001 緊急救援 (25 分)

複雜了一些的最短路,用優先隊列對查找最小dis的過程作了優化。dis[i]表示起點到i的最短路長度,pre[i]表示i的前驅,cnt[i]表示到達i的最短路條數,sum[i]表示最多的救援隊數目。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 505

using namespace std;

int n, m, s, d, x, y, z;
int num[N], path[N][N], dis[N], pre[N], cnt[N], sum[N];
bool vis[N];

struct Node {
    int key, value;
    Node(int k, int v) {
        key = k;
        value = v;
    }
    bool operator<(const Node &a) const { return value > a.value; }
};

void dijkstra() {
    pre[s] = -1;
    cnt[s] = 1;
    sum[s] = num[s];
    dis[s] = 0;
    priority_queue<Node> q;
    q.push(Node(s, 0));
    while (!q.empty()) {
        int k = q.top().key;
        q.pop();
        if (vis[k]) continue;
        vis[k] = true;
        for (int i = 0; i < n; ++i) {
            if (!vis[i]) {
                int cur_dis = dis[k] + path[k][i];
                int cur_sum = sum[k] + num[i];
                if (cur_dis < dis[i]) {
                    dis[i] = cur_dis;
                    pre[i] = k;
                    cnt[i] = cnt[k];
                    sum[i] = cur_sum;
                } else if (cur_dis == dis[i]) {
                    cnt[i] += cnt[k];
                    if (cur_sum > sum[i]) {
                        sum[i] = cur_sum;
                        pre[i] = k;
                    }
                }
                q.push(Node(i, dis[i]));
            }
        }
    }
    printf("%d %d\n", cnt[d], sum[d]);
    stack<int> stk;
    int k = d;
    while (k != -1) {
        stk.push(k);
        k = pre[k];
    }
    printf("%d", stk.top());
    stk.pop();
    while (!stk.empty()) {
        printf(" %d", stk.top());
        stk.pop();
    }
    printf("\n");
}

int main() {
    memset(path, INF, sizeof(path));
    memset(dis, INF, sizeof(dis));
    scanf("%d%d%d%d", &n, &m, &s, &d);
    for (int i = 0; i < n; ++i) scanf("%d", &num[i]);
    for (int i = 0; i < m; ++i) {
        scanf("%d%d%d", &x, &y, &z);
        path[x][y] = path[y][x] = z;
    }
    dijkstra();
    return 0;
}

[空間換時間] L2-002 鏈表去重 (25 分)

典型的空間換時間,若是按照是否重複而後一個一個刪除重複的,確定會超時。vis 數組作標記,沒重複就放到第一個隊列裏,重複的放到第二個隊列裏,最後讀一遍兩個隊列就好,複雜度差很少是 O(n)

#include <bits/stdc++.h>
using namespace std;

struct Node {
    int data, next;
};

int head, n, a, b, c;
vector<Node> node(100005);
vector<bool> vis(10005);
queue<int> q1, q2;

int main() {
    scanf("%d%d", &head, &n);
    while (n--) {
        scanf("%d%d%d", &a, &b, &c);
        node[a].data = b;
        node[a].next = c;
    }
    for (int i = head; i != -1; i = node[i].next) {
        if (!vis[abs(node[i].data)]) {
            vis[abs(node[i].data)] = true;
            q1.push(i);
        } else
            q2.push(i);
    }
    int pos = q1.front();
    q1.pop();
    printf("%05d %d ", pos, node[pos].data);
    while (!q1.empty()) {
        pos = q1.front();
        q1.pop();
        printf("%05d\n%05d %d ", pos, pos, node[pos].data);
    }
    printf("-1\n");
    if (!q2.empty()) {
        pos = q2.front();
        q2.pop();
        printf("%05d %d ", pos, node[pos].data);
        while (!q2.empty()) {
            pos = q2.front();
            q2.pop();
            printf("%05d\n%05d %d ", pos, pos, node[pos].data);
        }
        printf("-1");
    }
    return 0;
}

[貪心] L2-003 月餅 (25 分)

基本的結構體排序加貪心,可是這個 C++ 裏的小數真是奇怪啊,不知道精度發生了什麼神奇的錯誤,下面第一個代碼提交一直有一組數據過不了,把 int 換成 double 就對了???。。。??

#include <bits/stdc++.h>
using namespace std;

struct Node {
    int x, y;
    double z;
    bool operator<(const Node &node) const { return z > node.z; }
} a[1005];

int n, d;

int main() {
    cin >> n >> d;
    for (int i = 0; i < n; ++i) cin >> a[i].x;
    for (int i = 0; i < n; ++i) {
        cin >> a[i].y;
        a[i].z = a[i].y * 1.0 / a[i].x;
    }
    sort(a, a + n);
    double sum = 0;
    for (int i = 0; i < n; ++i) {
        if (d >= a[i].x) {
            d -= a[i].x;
            sum += a[i].y;
        } else {
            sum += d * a[i].z;
            break;
        }
    }
    cout << fixed << setprecision(2) << sum;
    return 0;
}

正確代碼,太坑了吧:

#include <bits/stdc++.h>
using namespace std;

struct Node {
    double x, y, z;  // x, y 換成 double
    bool operator<(const Node &node) const { return z > node.z; }
} a[1005];

int n;
double d;  // d 換成 double

int main() {
    cin >> n >> d;
    for (int i = 0; i < n; ++i) cin >> a[i].x;
    for (int i = 0; i < n; ++i) {
        cin >> a[i].y;
        a[i].z = a[i].y / a[i].x;
    }
    sort(a, a + n);
    double sum = 0;
    for (int i = 0; i < n; ++i) {
        if (d >= a[i].x) {
            d -= a[i].x;
            sum += a[i].y;
        } else {
            sum += d * a[i].z;
            break;
        }
    }
    cout << fixed << setprecision(2) << sum;
    return 0;
}

[搜索二叉樹前序轉後序] L2-004 這是二叉搜索樹嗎? (25 分)

本覺得上完數據結構的課應該就會各類樹了,結果發現本身仍是太年輕。這題按照二叉搜索樹的性質建樹,先試試是否是二叉搜索樹,再試試是否是二叉搜索樹的「鏡像」,若是最後能建成就順便輸出後序遍歷。

#include <bits/stdc++.h>

using namespace std;

int n, pre[1005], post[1005], cnt = 0;
bool flag;

void build(int l, int r) {
    if (l > r) return;
    int i = l + 1, j = r;
    if (!flag) {
        while (i <= r && pre[i] < pre[l]) ++i;
        while (l < j && pre[j] >= pre[l]) --j;
    } else {
        while (i <= r && pre[i] >= pre[l]) ++i;
        while (l < j && pre[j] < pre[l]) --j;
    }
    if (i - j != 1) return;
    build(l + 1, j);
    build(i, r);
    post[cnt++] = pre[l];
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) scanf("%d", &pre[i]);
    build(0, n - 1);
    if (cnt != n) {
        flag = true;
        cnt = 0;
        build(0, n - 1);
    }
    if (cnt != n)
        printf("NO\n");
    else {
        printf("YES\n");
        printf("%d", post[0]);
        for (int i = 1; i < cnt; ++i) printf(" %d", post[i]);
        printf("\n");
    }
    return 0;
}

[最長迴文子串] L2-008 最長對稱子串 (25 分)

馬拉車算法模板題,c(center)表示中間點,r(right)表示迴文串的右邊界。具體算法思路不說了,還有須要理解的就是 r 關於 c 的對稱點爲2 * c - i

#include <bits/stdc++.h>

using namespace std;

int manacher(string s) {
    string str = "$#";
    for (int i = 0; i < s.size(); ++i) {
        str.push_back(s[i]);
        str.push_back('#');
    }
    int c = 0, r = 0;
    vector<int> p(str.size());
    for (int i = 1; i < p.size(); ++i) {
        p[i] = r > i ? min(p[2 * c - i], r - i + 1) : 1;
        while (str[i - p[i]] == str[i + p[i]]) ++p[i];
        if (r - c + 1 < p[i]) {
            c = i;
            r = i + p[i] - 1;
        }
    }
    // return s.substr((2 * c - r) / 2, r - c);
    return r - c;
}

int main() {
    string s;
    getline(cin, s);
    cout << manacher(s);
    return 0;
}

[結構體排序] L2-009 搶紅包 (25 分)

結構體排序,輸入的錢是分爲單位,最後輸出時除以 100.0 獲得元。用結構體儲存每一個人的編號,收入,搶到紅包數。

#include <bits/stdc++.h>
#define N 10005

using namespace std;

struct Node {
    int key, sum, cnt;
    Node() : sum(0), cnt(0) {}
} a[N];

int n, k, x, y;

bool cmp(Node a, Node b) {
    if (a.sum == b.sum) {
        if (a.cnt == b.cnt)
            return a.key < b.key;
        return a.cnt > b.cnt;
    }
    return a.sum > b.sum;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        a[i].key = i;
        scanf("%d", &k);
        while (k--) {
            scanf("%d%d", &x, &y);
            a[i].sum -= y;
            a[x].sum += y;
            ++a[x].cnt;
        }
    }
    sort(a + 1, a + n + 1, cmp);
    for (int i = 1; i <= n; ++i)
        printf("%d %.2f\n", a[i].key, a[i].sum / 100.0);
    return 0;
}

[並查集] L2-010 排座位 (25 分)

並查集,若是兩我的是朋友關係就合併,不然,用flag數組標記兩人是敵人。最後直接判斷一下輸出就好。

#include <bits/stdc++.h>
#define N 105

using namespace std;

int n, m, k, x, y, z;
int f[N], _rank[N] = {0}, flag[N][N] = {false};

int _find(int x) {
    return x == f[x] ? x : f[x] = _find(f[x]);  // 路徑壓縮
}

void _union(int x, int y) {
    int f1 = _find(x), f2 = _find(y);
    if (f1 != f2) {
        if (_rank[f1] < _rank[f2])  // 按秩合併
            f[f1] = f2;
        else {
            f[f2] = f1;
            if (_rank[f1] == _rank[f2])
                ++_rank[f1];
        }
    }
}

int main() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; ++i)
        f[i] = i;
    while (m--) {
        scanf("%d%d%d", &x, &y, &z);
        if (z == 1)
            _union(x, y);
        else
            flag[x][y] = flag[y][x] = true;
    }
    while (k--) {
        scanf("%d%d", &x, &y);
        if (_find(x) == _find(y)) {
            if (!flag[x][y])
                printf("No problem\n");
            else
                printf("OK but...\n");
        } else {
            if (!flag[x][y])
                printf("OK\n");
            else
                printf("No way\n");
        }
    }
    return 0;
}

[最小堆] L2-012 關於堆的判斷 (25 分)

肝了我一晚,怎麼提交都是部分正確,我是真的無奈,直到看到有個題解:「用線性調整 heap 的話是不對的,題目要求是一個一個插入空的 MinHeap,因此只能插入,上浮,插入,上浮,插入,上浮。。。」,然而我試了一晚線性建堆。

思路很粗暴,先建堆(思路就是上面那句話,採用上浮的方式,加一個數浮一次),而後用 stringstream 把單詞分割出來裝進 vector,剩下就是簡單判斷。

#include <bits/stdc++.h>
#define N 1005

using namespace std;

int n, m, a[N];
string s;
stringstream ss;
vector<string> v;

void swim(int i) {
    int parent = (i - 1) / 2;
    if (parent >= 0 && a[parent] > a[i]) {
        swap(a[i], a[parent]);
        swim(parent);
    }
}

int toInt(string &s) {
    stringstream ss;
    ss << s;
    int x;
    ss >> x;
    return x;
}

int main() {
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
        swim(i);
    }
    cin.get();  // 吸取回車
    for (int i = 0; i < m; ++i) {
        getline(cin, s);
        ss << s;
        while (ss >> s) v.push_back(s);
        if (v[3] == "root") {
            if (toInt(v[0]) == a[0])
                cout << "T\n";
            else
                cout << "F\n";
        } else if (v[4] == "siblings") {
            int p1 = find(a, a + n, toInt(v[0])) - a;
            int p2 = find(a, a + n, toInt(v[2])) - a;
            if (((p1 - 1) >> 1) == ((p2 - 1) >> 1))
                cout << "T\n";
            else
                cout << "F\n";
        } else if (v[3] == "parent") {
            int p1 = find(a, a + n, toInt(v[0])) - a;
            int p2 = find(a, a + n, toInt(v.back())) - a;
            if ((p2 - 1) >> 1 == p1)
                cout << "T\n";
            else
                cout << "F\n";
        } else {
            int p1 = find(a, a + n, toInt(v[0])) - a;
            int p2 = find(a, a + n, toInt(v.back())) - a;
            if ((p1 - 1) >> 1 == p2)
                cout << "T\n";
            else
                cout << "F\n";
        }
        v.clear();
        ss.clear();
    }
    return 0;
}
相關文章
相關標籤/搜索