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