P9351 [JOI 2023 Final] Maze

P9351 [JOI 2023 Final] Maze

[JOI 2023 Final] Maze

题面翻译

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

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

模拟赛思维题

首先不难想到,对于每个点,它可以走到路径是一个正方形被挖掉四个角:

1 1 1
1 1 1 1 1
1 1 X 1 1
1 1 1 1 1
1 1 1

观察这个图,我们不难发现,所有边缘的点到x点的“八联通距离”是相等的

并且所有满足“八连通距离”$ \in [1,n] $ 的点都在这个图上。

我们用高度来描述每次盖章:
每次盖章之后,这个点的高度变为n
之后每走一步(无论黑白)高度都减少1
只有当高度大于0时可跨过黑点
高度等于0时只能走白点

有了这个性质,我们对每次bfs记录一个状态:
{x,y,dis,h}
分别表示每个点的横纵坐标,到这个点要盖几次章,到这个点的高度

然后对于每个点,只要它的高度不为0,就先消耗1的高度向四周bfs,如果高度为0,判断目标点是否为黑点:

若是黑点,则dis++,h=n-1(在u点应为n,在v点就是n-1)
若是白点,则直接走过去

然后注意一个细节:因为这题横纵坐标很大,要么用动态内存把二维压成一维,或者用map实现

但是因为map自带一个log,然后这题有点卡常,貌似过不去
所以要开数组然后二维压成一维

还有就是这题我bfs好像实现的不是很好,所以当数据出道极限(r=6e6,c=1)时,id可能出现12e6导致RE所以我直接把数组开到了12e6懒得重新写特判

然后这题就做完了

Code:

#include<bits/stdc++.h>
#define mp(x,y) ((x-1)*m+y)
const int N=2e7+5;
using namespace std;
int Map[N];
int vis[N];
int dx4[4]={-1,0,1,0},dy4[4]={0,1,0,-1};
int dx8[8]={-1,-1,-1,0,1,1,1,0},dy8[8]={-1,0,1,1,1,0,-1,-1};
char c[N];
int n,m,k,sx,sy,ex,ey;
bool check(int x,int y)
{
if(x<1||n<x)return 0;
if(y<1||m<y)return 0;
return 1;
}
struct Node{
int x,y,dis,h;
};
deque<Node> Q;
void bfs()
{
Q.push_back({sx,sy,1,0});
while(!Q.empty())
{
Node u=Q.front();Q.pop_front();
if(!check(u.x,u.y))continue;
if(vis[mp(u.x,u.y)])continue;
vis[mp(u.x,u.y)]=u.dis;
if(u.x==ex&&u.y==ey)return ;
if(u.h)
{
for(int i=0;i<8;i++)
{
Node v={dx8[i]+u.x,dy8[i]+u.y,u.dis,u.h-1};
if(check(v.x,v.y)&&(!vis[mp(v.x,v.y)]))
{
Q.push_back(v);
}
}
}
else
{
for(int i=0;i<4;i++)
{
Node v={dx4[i]+u.x,dy4[i]+u.y,u.dis+Map[mp(dx4[i]+u.x,dy4[i]+u.y)],0};
if(check(v.x,v.y)&&(!vis[mp(v.x,v.y)]))
{
if(Map[mp(v.x,v.y)]){v.h=k-1;Q.push_back(v);}
else {Q.push_front(v);}
}
}
}
}
}
void solve()
{
cin>>n>>m>>k;
cin>>sx>>sy;
cin>>ex>>ey;
for(int i=1;i<=n;i++)
{
scanf("%s",c+1);
for(int j=1;j<=m;j++)
{
Map[mp(i,j)]=(c[j]=='#');
}
}
bfs();
printf("%d",vis[mp(ex,ey)]-1);
}
int main()
{
//freopen("P9351.in","r",stdin);//freopen("P9351.out","w",stdout);
solve();
return 0;
}
posted @   liuboom  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示