P9351 [JOI 2023 Final] Maze

liuboom發表於2024-12-06

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;
}

相關文章