All for PAT秋考 | 1124 - 1130

涉及知识

  • 1125 贪心
  • 1126 DFS判连通(并查集、BFS也可)
  • 1127 二叉树BFS(zig-zag)
  • 1129 利用set排序(避免n次重排)
  • 1130 二叉树建树、中序遍历、string(erase、pop_back)


1124 Raffle for Weibo Followers (20 分)

利用set不重复的性质、find函数。

#include 
#include 
#include 
#include 

using namespace std;
set winners;
vector res;
char forwards[1010][21];

int main() {
    int mm, n_skip, win1;
    scanf("%d%d%d", &mm, &n_skip, &win1);
    for (int i = 1; i <= mm; ++i)
        scanf("%s", forwards[i]);
    int curr = win1;
    while (curr <= mm) {
        while (winners.find(forwards[curr]) != winners.end())
            curr++;
        winners.insert(forwards[curr]);
        res.emplace_back(forwards[curr]);
        curr += n_skip;
    }
    if (winners.empty()) {
        printf("Keep going...\n");
    } else {
        for (auto item: res) {
            puts(item.data());
        }
    }
    return 0;
}

1125 Chain the Ropes (25 分)

  • 两段绳子每次连结,它们的长度都要折半。越早选中的绳子,折半次数越多。

  • 因此,要让最后绳长最长,就要让长绳子少折半(两个较短绳连接折半后,一定还是剩余绳子中最短的!)。

  • 策略:从小到大排序,按序连结。

#include 
#include 
#include 

using namespace std;

int main() {
    int nn;
    scanf("%d", &nn);
    vector ropes;
    double temp;
    for (int i = 0; i < nn; ++i) {
        scanf("%lf", &temp);
        ropes.emplace_back(temp);
    }
    sort(ropes.begin(), ropes.end());
    double res = ropes[0];
    int ii = 1;
    while (ii < nn) {
        res = (res + ropes[ii++]) / 2;
    }
    printf("%d\n", int(res));
    return 0;
}

1126 Eulerian Path (25 分)

  1. 输入时,建图并计算各结点的度。
  2. 判连通。(DFS、并查集、BFS均可)
  3. 按照定义判断即可。
#include 

using namespace std;
bool graph[501][501] = {false}, visited[501] = {false};
int deg[501] = {0}, nn, mm;

void DFS(int src) {
    visited[src] = true;
    for (int i = 1; i <= nn; ++i) {
        if (!visited[i] && graph[src][i])
            DFS(i);
    }
}

int main() {
    int v1, v2;
    scanf("%d%d", &nn, &mm);
    for (int i = 0; i < mm; ++i) {
        scanf("%d%d", &v1, &v2);
        graph[v1][v2] = graph[v2][v1] = true;
        deg[v1]++, deg[v2]++;
    }
    DFS(1);
    bool connected = true;
    for (int i = 1; i <= nn; ++i) {
        if (!visited[i]) {
            connected = false;
            break;
        }
    }
    int cntOdd = 0;
    for (int i = 1; i <= nn; ++i) {
        printf("%d", deg[i]);
        printf(i == nn ? "\n" : " ");
        if (deg[i] % 2) cntOdd++;
    }
    if (!connected) puts("Non-Eulerian");
    else if (cntOdd == 0) puts("Eulerian");
    else if (cntOdd == 2) puts("Semi-Eulerian");
    else puts("Non-Eulerian");
    return 0;
}

1127 ZigZagging on a Tree (30 分)

  1. 由中序、后序序列建树,记录各深度结点数量
  2. 层序遍历,保存层序序列。
  3. 按照结点深度 (奇、偶),顺序/逆序的输出层序序列中的该层。
#include 
#include 
#include 

using namespace std;
struct Node {
    int key, depth;
    Node *lchild, *rchild;
};

int in_order[31], post_order[31], level_cnt[31] = {0};
vector zz_order;

Node *createBTree(int in_st, int in_ed, int post_st, int post_ed, int depth) {
    if (in_st > in_ed || post_st > post_ed) return NULL;
    if (in_st == in_ed || post_st == post_ed) {
        level_cnt[depth]++;
        return new Node{in_order[in_st], depth, NULL, NULL};
    }
    Node *root = new Node;
    int rkey = post_order[post_ed], pos = -1;
    for (int i = in_st; i <= in_ed; i++) {
        if (in_order[i] == rkey) {
            pos = i;
            break;
        }
    }
    int lsize = pos - in_st;
    root->key = rkey;
    root->depth = depth;
    root->lchild = createBTree(in_st, pos - 1, post_st, post_st + lsize - 1, depth + 1);
    root->rchild = createBTree(pos + 1, in_ed, post_st + lsize, post_ed - 1, depth + 1);
    level_cnt[depth]++;
    return root;
}

void LevelOrder(Node *root) {
    queue mq;
    mq.push(root);
    zz_order.emplace_back(root->key);
    while (!mq.empty()) {
        Node *curr = mq.front();
        mq.pop();
        if (curr->lchild) {
            mq.push(curr->lchild);
            zz_order.emplace_back(curr->lchild->key);
        }
        if (curr->rchild) {
            mq.push(curr->rchild);
            zz_order.emplace_back(curr->rchild->key);
        }
    }
}

int main() {
    int nn;
    scanf("%d", &nn);
    for (int i = 0; i < nn; ++i) scanf("%d", &in_order[i]);
    for (int i = 0; i < nn; ++i) scanf("%d", &post_order[i]);
    Node *root = createBTree(0, nn - 1, 0, nn - 1, 1);
    LevelOrder(root);
    int curr = 0;
    for (int i = 1; level_cnt[i]; ++i) {
        if (i % 2 == 0) { // l->r
            for (int j = 0; j < level_cnt[i]; ++j) {
                printf("%d", zz_order[curr]);
                printf(curr < nn - 1 ? " " : "\n");
                curr++;
            }
        } else { //r->l
            int t = curr;
            for (int j = level_cnt[i] - 1; j >= 0; --j) {
                printf("%d", zz_order[t + j]);
                printf(curr < nn - 1 ? " " : "\n");
                curr++;
            }
        }
    }
    return 0;
}

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

1128 N Queens Puzzle (20 分)

用不着保存整个棋盘!!!
对角线上位置的表示(diagonal):行号差的绝对值 == 列号差的绝对值
⚠️Nov. 1st二刷:若用abs函数,头文件用cstdlib,而不是cmath。

#include 
#include 

void judgeSolution() {
    int nn;
    scanf("%d", &nn);
    int board[1001];
    bool res = true;
    for (int i = 0; i < nn; ++i) {
        scanf("%d", &board[i]);
        if (res)
            for (int j = 0; j < i; ++j) {
                if (board[j] == board[i] || (fabs(i - j) == fabs(board[i] - board[j]))) {
                    res = false;
                    break;
                }
            }
    }
    puts(res ? "YES" : "NO");
}

int main() {
    int tt;
    scanf("%d", &tt);
    for (int i = 0; i < tt; ++i) {
        judgeSolution();
    }
    return 0;
}

1129 Recommendation System (25 分)

  • 每次加入新元素就重排,复杂度将达到O(n^2 log n),由于超时,仅16分!!!
  • 应该利用set的插入、删除仅O(n log n)的特性,重载Item的小于号,注意另外保存当前的cnts数组,供res.find(Item{temp, cnts[temp]})使用,删除再插入 来更新set中记录(set中元素不可修改)!!!
#include 
#include 

using namespace std;

struct Item {
    int id, cnt;

    bool operator<(const Item &i2) const {
        if (cnt != i2.cnt) return cnt > i2.cnt;
        return id < i2.id;
    }
};

int cnts[50001] = {0};
set res;

int main() {
    int nquery, max_k, temp;
    scanf("%d%d", &nquery, &max_k);
    scanf("%d", &temp);
    cnts[temp]++;
    res.insert(Item{temp, cnts[temp]});
    for (int i = 1; i < nquery; ++i) {
        scanf("%d", &temp);
        printf("%d:", temp);
        int kk = 0;
        for (auto item:res) {
            printf(" %d", item.id);
            kk++;
            if (kk == max_k) {
                printf("\n");
                break;
            }
        }
        if (kk < max_k) printf("\n");
        auto _find_ = res.find(Item{temp, cnts[temp]});
        if (_find_ != res.end()) {
            res.erase(_find_);
        }
        cnts[temp]++;
        res.insert(Item{temp, cnts[temp]});
    }
    return 0;
}
  • NOV 3 update: set的erase可以直接erase(key)
#include 
#include 

using namespace std;

struct Commodity {
    int id, cnt = 1;

    bool operator<(const Commodity &c2) const {
        return cnt != c2.cnt ? cnt > c2.cnt : id < c2.id;
    }
};
int main() {
    int nq, max_rec, cnts[50001] = {0}, temp;
    scanf("%d%d", &nq, &max_rec);
    set rec_list;
    for (int i = 0; i < nq; ++i) {
        scanf("%d", &temp);
        if(i > 0) {
            printf("%d:", temp);
            int j = 0;
            for(auto &item: rec_list) {
                printf(" %d", item.id);
                if(++j == max_rec) break;
            }
            puts("");
        }
        rec_list.erase(Commodity{temp, cnts[temp]});
        cnts[temp]++;
        rec_list.insert(Commodity{temp, cnts[temp]});
    }
    return 0;
}

1130 Infix Expression (25 分)

中缀表达式

  • 二叉树建树、中序遍历(给孩子不为空的结点加括号)
  • string(字符/字符串连结 +=)
  • string erase(0)、pop_back()去除最外面一层括号
  • ⚠️去括号要特判树仅有一个结点的情况
#include 
#include 
#include 

using namespace std;
struct Node {
    string data;
    int lchild, rchild;
} btree[21];
int nn;
string res;

void inorder(int root) {
    if (root == -1) return;
    bool _embrace = (btree[root].lchild != -1 || btree[root].rchild != -1);
    if (_embrace) res += '(';
    if (btree[root].lchild != -1) {
        inorder(btree[root].lchild);
    }
    res += btree[root].data;
    if (btree[root].rchild != -1) {
        inorder(btree[root].rchild);
    }
    if (_embrace) res += ')';
}

int main() {
    int nn, v1, v2;
    char temp_data[12];
    bool isRoot[21];
    fill(isRoot, isRoot + 21, true);
    scanf("%d", &nn);
    for (int i = 1; i <= nn; ++i) {
        scanf("%s%d%d", temp_data, &v1, &v2);
        btree[i] = Node{temp_data, v1, v2};
        if (v1 != -1) isRoot[v1] = false;
        if (v2 != -1) isRoot[v2] = false;
    }
    int root = -1;
    for (int i = 1; i <= nn; ++i) {
        if (isRoot[i]) {
            root = i;
            break;
        }
    }
    inorder(root);
    if (nn >= 2) {
        res.erase(0, 1); //注意
        res.pop_back();
    }
    puts(res.data());
    return 0;
}
  • NOV 3 update 原来写的太麻烦了 醉了
#include 
#include 
#include 

using namespace std;
struct Node {
    string data;
    int lc, rc;
} btree[21];
int root = 1;

void in_traverse(int curr) {
    if (root != curr && btree[curr].rc != -1) printf("(");
    if (btree[curr].lc != -1) in_traverse(btree[curr].lc);
    printf("%s", btree[curr].data.data());
    if (btree[curr].rc != -1) in_traverse(btree[curr].rc);
    if (root != curr && btree[curr].rc != -1) printf(")");
}

int main() {
    int nn;
    bool isRoot[21];
    fill(isRoot, isRoot + 21, true);
    scanf("%d", &nn);
    char str[12];
    int lc, rc;
    for (int i = 1; i <= nn; ++i) {
        scanf("%s%d%d", str, &lc, &rc);
        btree[i].data = str, btree[i].lc = lc, btree[i].rc = rc;
        isRoot[lc] = isRoot[rc] = false;
    }
    while (!isRoot[root]) root++;
    in_traverse(root);
    return 0;
}

你可能感兴趣的:(All for PAT秋考 | 1124 - 1130)