1. 程式人生 > 其它 >7250. 【USACO 2020 December Contest, Gold】Replication

7250. 【USACO 2020 December Contest, Gold】Replication

Description&&Data Constraint

Solution

首先我們可以求出每個點距離最近的岩石的距離,來判斷能否走到這個點。

同時因為機器人可以放置在任何一個起始位置,所以對於每個不是岩石或者起始點的點,可以求出它到最近的起始點的距離,來表示初始機器人走到那個點的時間。

但走的時候要注意,只有能走到才能走。

就是說如果到達這個點的時候,副本機器人撞到岩石了,那麼這個點就不能繼續往下擴充套件了。

那麼什麼情況下是無法到達呢?

現在我們已經知道了當前點距離最近的起點的距離,那麼就可以算出產生出來的副本距離當前點的曼哈頓距離,也就是 \(\lfloor \dfrac{dis_{x,y}}{d}\rfloor\)

用這個去跟當前距離最近岩石的距離比較一下,如果大於等於距離最近岩石的距離,就說明副本機器人撞岩石了,就不用從這個點繼續擴充套件了。

上面的兩個都可以用 \(\text{bfs}\) 來處理。

那麼現在對於初始機器人可以直接走到的位置都已經處理出來了(即 \(dis_{i,j}\ge 0\) 的位置),我們離解決這題只剩下求出副本機器人到的位置數量。

注:首先避免重複,可以把算過的位置打上標記。

這裡我們考慮將 \(\text{bfs}\) 的方式調轉一下,對於初始機器人能到達的位置,從這個位置往外擴充套件來走到副本機器人能走到的位置。

而這個向外走的距離,要麼是到達此點時複製機器人的次數,或者是到最近的岩石距離減去 1,代表著岩石與當前位置之間的空位。

但此時的佇列並不一定滿足單調,所以要將佇列轉成優先佇列來模擬大根堆。

Code

#include<queue>
#include<cstdio>
#include<cstring>
#define N 1005
using namespace std;
struct node
{
	int x,y,dis;
};
struct node1
{
	int x,y,dis;
	friend bool operator <(const node1 &X,const node1 &Y) {return X.dis<Y.dis;}
};
queue<node> q_rock,q_robot;
priority_queue<node1> getans;
int n,d,ans,fx[5]={0,1,-1,0,0},fy[5]={0,0,0,1,-1},a[N][N],torock[N][N],frorobot[N][N];
bool bj[N][N];
char s[N];
int main()
{
	memset(torock,-1,sizeof(torock));
	memset(frorobot,-1,sizeof(frorobot));
	scanf("%d%d",&n,&d);
	for (int i=1;i<=n;++i)
	{
		scanf("%s",s+1);
		for (int j=1;j<=n;++j)
		{
			if (s[j]=='#')
			{
				a[i][j]=1;
				node x;
				x.x=i;x.y=j;x.dis=0;
				q_rock.push(x);
				torock[i][j]=0;
			}
			if (s[j]=='S')
			{
				a[i][j]=1;
				node x;
				x.x=i;x.y=j;x.dis=0;
				q_robot.push(x);
				frorobot[i][j]=0;
			}
		}
	}
	while (!q_rock.empty())
	{
		node u=q_rock.front();q_rock.pop();
		for (int i=1;i<=4;++i)
		{
			int xx=u.x+fx[i],yy=u.y+fy[i];
			if (torock[xx][yy]<0&&xx>=1&&yy>=1&&xx<=n&&yy<=n)
			{
				torock[xx][yy]=u.dis+1;
				node x;
				x.x=xx;x.y=yy;x.dis=u.dis+1;
				q_rock.push(x);
			}
		}
	}
	while (!q_robot.empty())
	{
		node u=q_robot.front();q_robot.pop();
		if (u.dis/d>=torock[u.x][u.y]) continue;
		for (int i=1;i<=4;++i)
		{
			int xx=u.x+fx[i],yy=u.y+fy[i];
			if (frorobot[xx][yy]<0&&u.dis/d<torock[xx][yy]&&!a[xx][yy])
			{
				frorobot[xx][yy]=u.dis+1;
				node x;
				x.x=xx;x.y=yy;x.dis=u.dis+1;
				q_robot.push(x);
			}
		}
	}
	for (int i=1;i<=n;++i)
		for (int j=1;j<=n;++j)
			if (frorobot[i][j]>=0)
			{
				node1 x;
				x.x=i;x.y=j;x.dis=min(frorobot[i][j]/d,torock[i][j]-1);
				getans.push(x);
				bj[i][j]=true;
				++ans;
			}
	while (!getans.empty())
	{
		node1 u=getans.top();getans.pop();
		if (!u.dis) continue;
		for (int i=1;i<=4;++i)
		{
			int xx=u.x+fx[i],yy=u.y+fy[i];
			if (!bj[xx][yy]&&!a[xx][yy])
			{
				bj[xx][yy]=true;
				node1 x;
				x.x=xx;x.y=yy;x.dis=u.dis-1;
				getans.push(x);
				++ans;
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}