1. 程式人生 > 其它 >AtCoder Beginner Contest 213

AtCoder Beginner Contest 213

C - Reorder Cards

本題考查離散化,我們將所有出現過的\(x\)\(y\)分別存下來並排序去重,給它們重新編號並輸出即可。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
pair<int, int> V[MAXN];
int main(int argc, char *argv[]) {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int h, w, n;
    cin >> h >> w >> n;
    vector<int> X, Y;
    for (int i = 1; i <= n; ++i) {
        int x, y;
        cin >> x >> y;
        V[i] = {x, y};
        X.push_back(x);
        Y.push_back(y);
    }
    // vector排序並去重
    auto discrete = [](vector<int> &V) -> void {
        sort(V.begin(), V.end());
        V.erase(unique(V.begin(), V.end()), V.end());
    };
    discrete(X);
    discrete(Y);
    // 重新編號
    auto getIdx = [](vector<int> &V, int x) -> int {
        return lower_bound(V.begin(), V.end(), x) - V.begin() + 1;
    };
    for (int i = 1; i <= n; ++i) {
        auto [x, y] = V[i];
        cout << getIdx(X, x) << ' ' << getIdx(Y, y) << '\n';
    }
    system("pause");
    return 0;
}

D - Takahashi Tour

按照題意模擬即可,注意邊存下來後要先遍歷小的,可以利用\(vector\)存邊並排序,題目給的第二個條件其實就是\(dfs\)回溯的過程。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
bool vis[MAXN];
vector<int> e[MAXN], path;
void dfs(int u) {
    for (int v: e[u]) {
        if (vis[v]) continue;
        vis[v] = true;
        path.push_back(v); // 先到v
        dfs(v);
        path.push_back(u); // 回到u
    }
}
int main(int argc, char *argv[]) {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for (int i = 1; i <= n; ++i) {
        sort(e[i].begin(), e[i].end());
    }
    vis[1] = true;
    path.push_back(1);
    dfs(1);
    for (auto it: path) {
        cout << it << ' ';
    }
    system("pause");
    return 0;
}

E - Stronger Takahashi

本題初看沒啥思路,但是我們可以重新理解下題目所說的破壞一個\(2×2\)的矩陣,我們可以把這個操作理解為花費\(1\)的費用使得接下來周圍的幾個點全部可達。

那麼本題就可以用最短路解決了,考慮如下建邊的方式:

\(\bullet\) 對於每個點,我們從它向四周連一條費用為\(0\)的邊,如果是牆壁則不連邊。

\(\bullet\) 對於每個點,我們從它向四周\(5×5\)的矩陣連一條費用為\(1\)的邊,注意矩陣周圍四個角不連。

然後跑最短路即可。

為什麼是\(5×5\)呢,可以看下圖:

假設當前我們所在位置在下圖紅色點。

通過操作二,我們可以到達如下幾個矩陣:




\(\cdots\)

那麼最終它全部可達的點就如下圖所示:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500 * 500 + 50;
struct edge {
    int to, next, val;
}e[MAXN << 5];
int head[MAXN], idx;
void addedge(int u, int v, int w) {
	e[++idx] = edge{v, head[u], w};
	head[u] = idx;
}
struct GraphNode {
	int u, dist;
	bool operator <(const GraphNode &oth) const {
		return oth.dist < dist;
	}
};
bool vis[MAXN];
int dist[MAXN];
void dijkstra(int s) {
    priority_queue<GraphNode> Q;
	memset(vis, false, sizeof(vis));
    memset(dist, 0x3f, sizeof(dist));
    dist[s] = 0, Q.push({s, dist[s]});
    while (!Q.empty()) {
        int u = Q.top().u; Q.pop();
        if (vis[u]) continue;
		vis[u] = true;
        for (int i = head[u]; i; i = e[i].next) {
            int v = e[i].to, w = e[i].val;
            if (dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
                Q.push({v, dist[v]});
            }
        }
    }
}
char g[505][505];
int n, m, ID[505][505];
int main(int argc, char *argv[]) {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    int cnt = 0;
    // 對每個點編號方便建圖
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            cin >> g[i][j];
            ID[i][j] = ++cnt;
        }
    }
    // 方向陣列
    int d[4][2] = {
        {0, 1}, {0, -1}, {1, 0}, {-1, 0}
    };
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            for (int k = 0; k < 4; ++k) {
                int nx = i + d[k][0], ny = j + d[k][1];
                if (1 <= nx && nx <= n && 1 <= ny && ny <= m) {
                    if (g[nx][ny] == '.') {
                        addedge(ID[i][j], ID[nx][ny], 0);
                    }
                }
            }
            // 這裡矩陣建邊直接for迴圈比較方便
            for (int x = -2; x <= 2; ++x) {
                for (int y = -2; y <= 2; ++y) {
                    if (abs(x) == 2 && abs(y) == 2) continue; // 如果是角落則不建邊
                    int nx = i + x, ny = j + y;
                    if (1 <= nx && nx <= n && 1 <= ny && ny <= m) {
                        addedge(ID[i][j], ID[nx][ny], 1);
                    }
                }
            }
        }
    }
    dijkstra(1);
    cout << dist[n * m] << '\n';
    system("pause");
    return 0;
}