AtCoder Beginner Contest 213
阿新 • • 發佈:2021-08-09
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;
}