题意
给定一个n*m的海滩,海棠上有空地’.‘,以及礁石’#’
以及若干别人的沙滩床,占两格,有左右排列L,R,以及上下排列U,D这两种。
现要从这海滩上找两个相邻的空地’.',铺一张沙滩床。
可以让别的游客挪位置。有两种,旋转,平移,分别需要花费p和q的不舒适度。
问最少需要花费多少不适合度,才能找到一个空地来放沙滩床。如果找不到,输出-1。
思路
发现1:每个沙滩床,最多只需要移动一次。因为如果可以移动两次,证明本身就存在一个空地了。
发现2:我们把沙滩床的移动,等价为空地的移动。
发现3:可以建立一个超级源地,计算每个位置到超级源点的距离。
最后,只需要求相邻两个点,的最小距离和,即可。
建立超级源点,和构图,是本题的关键~
代码
源自 nanfeng1997
/* Generated by powerful Codeforces Tool
* Author: SmartNanfeng
* Time: 2022-10-23 15:50:11
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#ifdef LOCAL
#include <debugger>
#else
#define debug(...) 42
#endif
template <typename T> void chkmax(T &x, T y) { x = max(x, y); }
template <typename T> void chkmin(T &x, T y) { x = min(x, y); }
void solve() {
int n, m, p, q; cin >> n >> m >> p >> q;
vector<string> s(n); for (auto &x: s) cin >> x;
// build edges
vector<vector<pair<int, int> > > son(n * m + 1);
auto add = [&] (int i, int j, int v, int w) -> void {
if (i < 0 || i >= n || j < 0 || j >= m) return ;
int u = i * m + j;
son[u].emplace_back(v, w);
};
for (int i = 0; i < n; i ++ ) {
for (int j = 0; j < m; j ++ ) {
int now = i * m + j;
if (s[i][j] == 'L') {
add(i - 1, j + 1, now, p); add(i + 1, j + 1, now, p); add(i, j + 2, now, q);
} else if (s[i][j] == 'R') {
add(i - 1, j - 1, now, p); add(i + 1, j - 1, now, p); add(i, j - 2, now, q);
} else if (s[i][j] == 'U') {
add(i + 1, j - 1, now, p); add(i + 1, j + 1, now, p); add(i + 2, j, now, q);
} else if (s[i][j] == 'D') {
add(i - 1, j - 1, now, p); add(i - 1, j + 1, now, p); add(i - 2, j, now, q);
} else if (s[i][j] == '.') {
son[n * m].emplace_back(now, 0);
}
}
}
struct node {
int u; ll dis;
bool operator < (const node &T) const {
return dis > T.dis;
}
};
// cal dis[x][y] from super src point [n][m]
priority_queue<node> pq;
pq.push({n * m, 0});
vector<bool> st(n * m + 1, false);
vector<ll> dist(n * m + 1, 1E18);
dist[n * m] = 0;
while (!pq.empty()) {
auto [u, dis] = pq.top(); pq.pop();
if (st[u]) continue;
st[u] = true;
for (auto &[v, w]: son[u]) {
if (dist[v] > dis + w) {
dist[v] = dis + w;
pq.push({v, dist[v]});
}
}
}
// cal min dis[x][y] + dis[a][b], which (x,y) and (a,b) are neighbor points.
auto get = [&] (int i, int j) -> ll {
if (i < 0 || i >= n || j < 0 || j >= m) return 1E18;
int u = i * m + j;
return dist[u];
};
ll ans = 1E18;
for (int i = 0; i < n; i ++ ) {
for (int j = 0; j < m; j ++ ) {
int u = i * m + j;
chkmin(ans, dist[u] + get(i + 1, j));
chkmin(ans, dist[u] + get(i, j + 1));
}
}
if (ans >= 1E17) ans = -1;
cout << ans << "\n";
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int T = 1; // cin >> T;
while (T --) solve();
return 0;
}
/*
*
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/