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 @ 2024-12-06 11:49  liuboom  阅读(19)  评论(0)    收藏  举报