F. The Beach(图论/最短路)

题目
参考

题意

给定一个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 
 *   ┃        ┣┓
 *    ┃        ┏┛
 *     ┗┓┓┏━┳┓┏┛ + + + +
 *    ┃┫┫ ┃┫┫
 *    ┗┻┛ ┗┻┛+ + + +
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值