【APCS】2024年1月題解

P1:遊戲選角

印出「x 和 y 的平方和」第二大的 x 和 y。
ZeroJudge 連結

解法一:用 struct
#include <iostream>
#include <algorithm>
using namespace std;

struct Pair{
    int x, y;
};

bool cmp(Pair a, Pair b){
    return a.x * a.x + a.y * a.y > b.x * b.x + b.y * b.y;
}

int main(){
    int n;
    cin >> n;
    Pair a[n];
    for(int i=0; i<n; i++){
        cin >> a[i].x >> a[i].y;
    }
    sort(a, a+n, cmp);
    cout << a[1].x << ' ' <<  a[1].y << '\n';
}
解法二:用 vector
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool cmp(vector<int> a, vector<int> b){
    return a[2] > b[2];
}

int main(){
    int n;
    cin >> n;
    vector<vector<int>> v(n, vector<int>(3));
    for(int i=0; i<n; i++){
        cin >> v[i][0] >> v[i][1];
        v[i][2] = v[i][0] * v[i][0] + v[i][1] * v[i][1];
    }
    sort(v.begin(), v.end(), cmp);
    cout << v[1][0] << ' ' <<  v[1][1] << '\n';
}

P2:蜜蜂觀察

輸出蜜蜂經過的字母(碰到牆壁該行動會停在原地)。
ZeroJudge 連結

#include <iostream>
#include <string>
using namespace std;

int main(){
    int m, n, k;
    cin >> m >> n >> k;
    char a[m][n];
    string s;
    for(int i=0; i<m; i++){
        cin >> s;
        for(int j=0; j<n; j++){
            a[i][j] = s[j]; 
        }
    }
    int nx = m-1, ny = 0, step, count = 0;
    bool visited[58] = {false}; // 65~90, 97~122 -> 0~25, 32~57
    int dx[6] = {-1, 0, 1, 1, 0, -1};
    int dy[6] = {0, 1, 1, 0, -1, -1};
    while(k--){
        cin >> step;
        if(nx + dx[step] >= 0 && nx + dx[step] < m && ny + dy[step] >= 0 && ny + dy[step] < n){
            nx += dx[step];
            ny += dy[step];
        }
        cout << a[nx][ny];
        if(!visited[a[nx][ny]-65]){
            visited[a[nx][ny]-65] = true;
            count++;
        }
    }
    cout << '\n' << count << '\n';
}

P3:邏輯電路

求最大延遲時間、輸出端口的數值。
輸入端口 p 個 (編號 1 到 p)
邏輯閘 q 個 (編號 p+1 到 p+q)
輸出端口 r 個 (編號 p+q+1 到 p+q+r)
ZeroJudge 連結

使用到的觀念:【筆記】拓撲排序 (Topological Sort)

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

struct node {
    int value;
    int type;
    vector<int> out;
    vector<int> in;
    int indegree;
    int delay;
};

int main(){
    int p, q, r, m;
    cin >> p >> q >> r >> m;
    vector<node> v(p+q+r);
    for(int i=0; i<p; i++) cin >> v[i].value;
    for(int i=p; i<p+q; i++) cin >> v[i].type;
    while(m--){
        int a, b;
        cin >> a >> b;
        a--, b--; // 0-based
        v[a].out.push_back(b);
        v[b].in.push_back(a);
        v[b].indegree++;
    }
    queue<int> qu;
    vector<int> ans;
    for(int i=0; i<p+q+r; i++){
        if(v[i].indegree == 0) qu.push(i);
    }
    while(!qu.empty()){
        int now = qu.front();
        ans.push_back(now);
        qu.pop();
        for(int i : v[now].out){
            if(--v[i].indegree == 0) qu.push(i);
        }
    }
    int maxDelay = 0;
    for(int i : ans){
        if(v[i].type == 1){ // AND
            v[i].value = v[v[i].in[0]].value & v[v[i].in[1]].value;
            v[i].delay = max(v[v[i].in[0]].delay, v[v[i].in[1]].delay) + 1;
        }else if(v[i].type == 2){ // OR
            v[i].value = v[v[i].in[0]].value | v[v[i].in[1]].value;
            v[i].delay = max(v[v[i].in[0]].delay, v[v[i].in[1]].delay) + 1;
        }else if(v[i].type == 3){ // XOR
            v[i].value = v[v[i].in[0]].value ^ v[v[i].in[1]].value;
            v[i].delay = max(v[v[i].in[0]].delay, v[v[i].in[1]].delay) + 1;
        }else if(v[i].type == 4){ // NOT
            v[i].value = 1 - v[v[i].in[0]].value;
            v[i].delay = v[v[i].in[0]].delay + 1;
        }
        maxDelay = max(maxDelay, v[i].delay);
    }
    cout << maxDelay << '\n';
    for(int i=p+q; i<p+q+r; i++){
        cout << v[v[i].in[0]].value << ' ';
    }
}

P4:合併成本

挑兩個「相鄰」數字合併,花費 |u-v|,變成 u+v,求最小花費。
ZeroJudge 連結

解法:動態規劃 (DP)
cost[i][j] = 合併第 i 到 j 個數的最小花費
為了確保每一步的合併做出最佳選擇 遍歷尋找分割點
將 [i, j] 分割成 [i, k] 和 [k+1, j]
計算這兩部分分別合併成一個數字的花費,再加上最後合併這兩部分的額外花費。

#include <iostream>
#include <cstring>
using namespace std;

int a[100];
int cost[100][100];

int dp(int l, int r){
    if(l == r) return 0;
    if(cost[l][r] != -1) return cost[l][r];
    int Min = 2000 * 99;
    for(int k=l; k<r; k++){
        int u = 0, v = 0;
        for(int i=l; i<=k; i++) u += a[i];
        for(int i=k+1; i<=r; i++) v += a[i];
        Min = min(Min, dp(l, k) + dp(k+1, r) + abs(u - v));
    }
    cost[l][r] = Min;
    return Min;
}

int main(){
    int n;
    cin >> n;
    for(int i=0; i<n; i++){
        cin >> a[i];
    }

    memset(cost, -1, sizeof(cost));

    cout << dp(0, n-1) << '\n';
}
發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *