图论杂记 2025.8.5始
Re:从零开始的图论生活
0.1 洛谷P3638 [APIO2013] 机器人
题面太长,不放
考虑到每个机器人最终停下来的位置是固定的,可以记忆化搜索把终点存下来。
具体的,代码中 \(dp_{i,j,k}\) 表示在 \((i,j)\),朝 \(k\) 方向的终点。
因为合并的机器人是连续的,可以使用一种类似于区间 \(DP\) 的东西来对最优答案进行转移。
(有大佬说像斯坦纳树,但我不会)
所以建立分层图之后,\(dis_{i,j,k}\) 表示 \(i \to j\) 间的机器人走到 \(k\) 点的最小距离,这里 \(k\) 表示能走地方的编号(见代码 \(recpos\) 数组)。
\(\huge \mathscr{Code}\)
#include<bits/stdc++.h>
using namespace std;
const int N = 505, INF = 1e9;
int dx[4] = { -1,0,1,0 }, dy[4] = { 0,1,0,-1 };
int n, w, h, k, mp[N][N], dp[N][N][4], vis[N][N][4];
int recpos[N][N], tot;
char ch;
vector<int> g[N * N * 4];
int Memdfs(int x, int y, int dir) {
if (vis[x][y][dir]) return dp[x][y][dir] = -INF; // loop
if (dp[x][y][dir] != -1) return dp[x][y][dir];
vis[x][y][dir] = 1;
int kx = x + dx[dir], ky = y + dy[dir];
if (mp[kx][ky] == 0) dp[x][y][dir] = recpos[x][y];
else if (mp[kx][ky] == 11) dp[x][y][dir] = Memdfs(kx, ky, (dir + 3) % 4);
else if (mp[kx][ky] == 12) dp[x][y][dir] = Memdfs(kx, ky, (dir + 1) % 4);
else dp[x][y][dir] = Memdfs(kx, ky, dir);
vis[x][y][dir] = 0;
return dp[x][y][dir];
}
int dis[10][10][N * N], q1[N * N], q2[N * N];
bool inq[N * N];
void SPFA(int* s) {
int cnt = 0;
for (int i = 1; i <= tot; i++) {
if (s[i] < 0x3f3f3f3f) {
q1[++cnt] = i;
inq[i] = true;
}
}
sort(q1 + 1, q1 + cnt + 1, [&](int a, int b) { return s[a] < s[b]; });
int cur = 1, hd = 1, tl = 0;
while (cur <= cnt || hd <= tl) {
int t = INF;
if (cur <= cnt && (hd > tl || s[q1[cur]] <= s[q2[hd]])) t = q1[cur], cur++;
else t = q2[hd], hd++;
inq[t] = false;
for (int e : g[t]) {
if (s[e] > s[t] + 1) {
s[e] = s[t] + 1;
if (!inq[e]) inq[e] = true, q2[++tl] = e;
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> k >> w >> h;
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) {
cin >> ch;
int c;
if (ch >= '1' && ch <= '9') c = ch - '0';
else if (ch == 'A') c = 11;
else if (ch == 'C') c = 12;
else if (ch == '.') c = 10;
else c = 0;
if (c) recpos[i][j] = ++tot;
mp[i][j] = c;
}
}
memset(dp, -1, sizeof(dp));
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) {
if (mp[i][j]) {
Memdfs(i, j, 0);
Memdfs(i, j, 1);
Memdfs(i, j, 2);
Memdfs(i, j, 3);
}
}
}
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) {
if (mp[i][j]) {
for (int d = 0; d < 4; d++) {
if (dp[i][j][d] != -INF && dp[i][j][d] != recpos[i][j]) {
g[recpos[i][j]].push_back(dp[i][j][d]);
}
}
}
}
}
memset(dis, 0x3f, sizeof(dis));
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) {
if (mp[i][j] >= 1 && mp[i][j] <= 9) {
dis[mp[i][j]][mp[i][j]][recpos[i][j]] = 0;
}
}
}
for (int len = 1; len <= k; len++) {
for (int l = 1, r = l + len - 1; r <= k; l++, r++) {
for (int mid = l; mid < r; mid++) {
for (int i = 1; i <= tot; i++) {
dis[l][r][i] = min(dis[l][r][i], dis[l][mid][i] + dis[mid + 1][r][i]);
}
}
SPFA(dis[l][r]);
}
}
int ans = INF;
for (int i = 1; i <= tot; i++) ans = min(ans, dis[1][k][i]);
cout << (ans == INF ? -1 : ans);
return 0;
}

浙公网安备 33010602011771号