题意
传送门 Codeforces 1754F The Beach
题解
观察到一张浴床至多移动一次,否则可以构造出花费更小的方案。将浴床的移动,看作将一个空位 ‘.’ 移动到了之前浴床的某一半所占据的格子上。方案的构造可能涉及多个浴床的移动。考虑建图,求解从所有空位 ‘.’ 出发,经过不断地移动抵达某个位置的花费。
对于图中相邻格子,两者横纵坐标求和的奇偶性不同。位于某一个位置的空位 ‘.’ 只能移动到与其奇偶性相同的位置上。 那么枚举相邻格子,答案为空位 ‘.’ 抵达两者的花费之和。总时间复杂度 O ( m n log ( m n ) ) O\big( mn\log(mn)\big) O(mnlog(mn))。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<ll, int>;
struct Edge {
int to, cost;
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
int p, q;
cin >> p >> q;
vector<string> mat(n);
for (int i = 0; i < n; ++i) {
cin >> mat[i];
}
auto judge = [&](int x, int y) {
return 0 <= x && x < n && 0 <= y && y < m;
};
vector<vector<Edge>> g(n * m);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
auto c = mat[i][j];
if (c != 'L' && c != 'U') {
continue;
}
set<pair<int, int>> st;
if (c == 'L') {
st.insert({i, j});
st.insert({{i, j + 1}});
} else {
st.insert({i, j});
st.insert({i + 1, j});
}
for (auto [x, y] : st) {
for (int dx = -1; dx <= 1; ++dx) {
for (int dy = -1; dy <= 1; ++dy) {
if (abs(dx) + abs(dy) > 1) {
continue;
}
int nx = x + dx, ny = y + dy;
if (!judge(nx, ny)) {
continue;
}
if (st.count({nx, ny})) {
continue;
}
if (mat[nx][ny] == '#') {
continue;
}
for (auto [x2, y2] : st) {
if (abs(x2 - nx) + abs(y2 - ny) == 1) {
continue;
}
int c = nx == x2 || ny == y2 ? q : p;
g[nx * m + ny].push_back({x2 * m + y2, c});
}
}
}
}
}
}
vector<ll> ds(n * m, 1e18);
priority_queue<P, vector<P>, greater<P>> que;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (mat[i][j] == '.') {
que.push({0ll, i * m + j});
ds[i * m + j] = 0;
}
}
}
vector<int> upd(n * m);
while (!que.empty()) {
auto [d, v] = que.top();
que.pop();
if (upd[v]) {
continue;
}
upd[v] = 1;
for (auto [to, cost] : g[v]) {
auto d2 = d + cost;
if (ds[to] > d2) {
ds[to] = d2;
que.push({d2, to});
}
}
}
ll res = 1e18;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (i + 1 < n) {
res = min(res, ds[i * m + j] + ds[(i + 1) * m + j]);
}
if (j + 1 < m) {
res = min(res, ds[i * m + j] + ds[i * m + (j + 1)]);
}
}
}
cout << (res == 1e18 ? -1 : res) << '\n';
return 0;
}