首页 > 其他分享 >P9351 [JOI 2023 Final] Maze 题解

P9351 [JOI 2023 Final] Maze 题解

时间:2024-10-18 10:49:56浏览次数:6  
标签:std tx ty int 题解 P9351 2023 first dis

Description

给定一张 \(R\times C\) 的地图,其中 . 可以走,而 # 不能走。一次操作可以将 \(N \times N\) 的正方形范围内所有点变成 .,给定起点和终点,求最少需要几次操作使得起点和终点连通(只能上下左右移动)。

\(R\times C\le 6\times 10^6\),\(N\le R\le C\)。

Solution

先考虑怎么暴力求出答案。

假设当前从起点走到了 \((x,y)\),那么 \((x,y)\) 此时一定为白点,下一步可以花 \(0\) 的代价走到一个初始就是白色的点。

或者花费 \(1\) 的代价在 \((x,y)\) 周围涂白一个大小为 \(N\) 的正方形并走到这个正方形里的任何一个点 \((x_0,y_0)\),容易发现 \((x,y)\) 能走到 \((x_0,y_0)\) 当且仅当 \(|x-x_0|,|y-y_0|\leq N\) 且 \(\min\left\{|x-x_0|,|y-y_0|\right\}\leq N-1\)。

建图跑 01bfs 可以得到一个 \(O(RCN^2)\) 的做法。过不了。

由于算法慢在二操作的边数过多,所以考虑把二操作的长距离走法优化成多次走相邻格子的过程。

因为 \((x,y)\) 能走到 \((x_0,y_0)\) 当且仅当 \(|x-x_0|,|y-y_0|\leq N\) 且 \(\min\left\{|x-x_0|,|y-y_0|\right\}\leq N-1\),所以 \((x,y)\to (x_0,y_0)\) 可以看成先走到四联通格子,再走至多 \(N-1\) 步八联通。

于是把步数作为第一关键字,走的八联通步数看作第二关键字跑最短路即可。

dijkstra 直接做可以做到 \(O(RC\log RC)\),但是可能能用 01bfs 做到 \(O(RC)\)。

时间复杂度:\(O(RC\log RC)\)。

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxT = 6e6 + 5, kMaxN = 3e3 + 5;
const int kD4[][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
const int kD8[][2] = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}, {0, 1}, {0, -1}, {1, 0}, {-1, 0}};

int n, m, k;
int sx, sy, tx, ty;
std::vector<int> G[kMaxT];
std::string s[kMaxN];

void dijkstra() {
  std::vector<std::vector<std::pair<int, int>>> dis(n + 1, std::vector<std::pair<int, int>>(m + 1));
  std::vector<std::vector<bool>> vis(n + 1, std::vector<bool>(m + 1));
  std::priority_queue<std::tuple<int, int, int, int>> q;
  for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= m; ++j)
      dis[i][j] = {1e9, 1e9};
  dis[sx][sy] = {0, k - 1};
  q.emplace(0, -(k - 1), sx, sy);
  for (; !q.empty();) {
    auto [d, w, x, y] = q.top();
    q.pop();
    if (vis[x][y]) continue;
    vis[x][y] = 1;
    for (auto [dx, dy] : kD4) {
      int tx = x + dx, ty = y + dy;
      if (tx < 1 || tx > n || ty < 1 || ty > m) continue;
      if (s[tx][ty] == '.') {
        std::pair<int, int> p = {dis[x][y].first, k - 1};
        if (dis[tx][ty] > p) {
          dis[tx][ty] = p;
          q.emplace(-p.first, -p.second, tx, ty);
        }
      }
      std::pair<int, int> p = {dis[x][y].first + 1, 0};
      if (dis[tx][ty] > p) {
        dis[tx][ty] = p;
        q.emplace(-p.first, -p.second, tx, ty);
      }
    }
    if (dis[x][y].second < k - 1) {
      for (auto [dx, dy] : kD8) {
        int tx = x + dx, ty = y + dy;
        if (tx < 1 || tx > n || ty < 1 || ty > m) continue;
        std::pair<int, int> p = {dis[x][y].first, dis[x][y].second + 1};
        if (dis[tx][ty] > p) {
          dis[tx][ty] = p;
          q.emplace(-p.first, -p.second, tx, ty);
        }
      }
    }
  }
  std::cout << dis[tx][ty].first << '\n';
}

void dickdreamer() {
  std::cin >> n >> m >> k >> sx >> sy >> tx >> ty;
  for (int i = 1; i <= n; ++i) {
    std::cin >> s[i];
    s[i] = " " + s[i];
  }
  dijkstra();
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:std,tx,ty,int,题解,P9351,2023,first,dis
From: https://www.cnblogs.com/Scarab/p/18473807

相关文章

  • NordicOI 2023
    A.ChatNOI题目描述给定一个由\(N\)个小写英文单词组成的文章,我们定义一个\(k+1\)个单词的可能性为其在文章中的出现次数。现在给出一个句子的前\(k\)个单词,你要补全后面的\(m\)个单词,使得其中所有长度为\(k+1\)的字串的可能性最小值最大。有\(Q\)次询问。思路因......
  • CF571B-题解
    CF571B题意给定数组\(A\)和值\(k\),你可以重排\(A\)中的元素,使得\(\displaystyle\sum_{i=1}^{n-k}|A_i-A_{i+k}|\)最小。输出最小值。思路\(A_i,A_{i+k}\)就等同于在将\(i\)模\(k\)的意义上把\(A\)分为若干组贪心的想要使\(\displaystyle\sum_{i=1}^{n-k}|A_i-A......
  • 【题解】Solution Set - NOIP2024集训Day56 哈希杂题
    【题解】SolutionSet-NOIP2024集训Day56哈希杂题https://www.becoder.com.cn/contest/5640「CF568C」NewLanguage做过的2-sat。「NOI2024」集合做过。做法见提交记录。「CSP-S2022」星战简要题意:给定有向图。修改使一条边失效/恢复;使一个点的所有入边......
  • [YDOI R1] Necklace 题解
    题目传送门前置芝士二项式定理:\((a+b)^n=\sum\limits_{i=0}^{n}C^i_n\timesa^i\timesb^{n-i}\)快速幂Meaning有\(n\)种珠子,每种有\(a_i\)颗,且美丽值为\(v_i\)。任意两颗珠子不同(同种类也算不同)。每种珠子有一个漂亮值\(v_i\)。项链有一个美丽度,若第\(i\)种珠子......
  • Codeforces Round 893 (Div. 2)题解记录
    题目链接:https://codeforces.com/contest/1858A.Buttons从自身角度出发,我想赢就得保证我的按钮尽可能多所以,大家都优先按\(c\),然后分析先后顺序即可 #include<iostream> #include<string.h> #include<map> #include<vector> #include<set> #include<unordered_set> #......
  • [ABC134F] Permutation Oddness 题解
    [ABC134F]PermutationOddness题解朴素的想法显然是状压dp,枚举选择的子集,但复杂度不可接受。考虑优化。注意到对于\(p_i\),它的贡献只会有两种可能性,\(+p_i,-p_i\)。于是初步的想法是按照\(p_i\)的正负性选择分类。考虑到对于相同正负性的选择\(p\),其是等价的。于是我们......
  • P4229 某位歌姬的故事 题解
    P4229某位歌姬的故事题解\(n\le9\times10^8\),显然复杂度不与\(n\)相关。\(m\le500\),显然可以接受\(O(Tm^2)\)的做法。对于\([l,r]\),考虑套路地将端点离散化,使得复杂度只和关键点个数有关。考虑对于\([l,r,m]\),离散化后被分成了\(a_1,a_2,\cdots,a_p\)段,那么这些段的......
  • ZZJC新生训练赛第四场题解
    ZZJCACM新生训练赛-2024.10.16题目难度Easy(简单):B,C,D,GMedium(中等):A,EAnti-AK(防AK):EC题解题思路A页既可以是彩印也可以是黑白印,B页只能是彩印,所以只要比较A页彩印和A页黑白印的价格高低就好。因为a,b,x,y最大都是1e9,用int直接相乘的话会爆掉,所以......
  • DMA连续发送多帧但是只有最后一帧数据发出问题解决方法
    问题描述DMA连续发送多帧但是只有最后一帧数据发出原因分析DMA发送未完成时,下次DMA请求启动,导致之前的数据被放弃传输了解决办法创建DMA发送缓冲区,当启动DMA请求的时候,检测DMA设备是不是正在忙,如果正在忙,就把数据放入发送缓冲区等待,上次DMA发送完成的时会产生DMA发送完......
  • 【学校训练记录】10月个人训练赛3个人题解
    A:根据题意我们可知,第一种事件为从1到i的和,第二种事件为从y到i的和故我们可以通过前缀和来保存从i到i+1所化的时间。再遍历寻找最小值即可#include<bits/stdc++.h>#defineendl"\n"#defineintlonglongusingnamespacestd;intn,a[1010];voidsolve(){ cin>>n;......