题面
题解
首先这题放在图论专题难度就下降了一大个档次ww
我们注意到一点,就是如果你可以把两个点的位置记下来,一步操作之后,只会有四种可能的情况.
两个点的位置情况乍一看是 \(n^4\approx 3.9\times10^9\) 存不下,但是注意到一步操作之后,一定会在障碍点四周四个点或者边界上.
所以情况数只有 \((4m+4n)^2=4\times10^6\),完全可以接受.
然后我们的思路就是先预处理出所有点移动一步可能的位置,建图,bfs 求出每个点最小的步数,然后回答询问的时候枚举一下第一步的情况.
小常识:边权为1的图的最短路可以用bfs \(O(n)\) 求
到多个点的最小步数直接把所有终点塞进去bfs就好了
时间复杂度 \(O((4m+4n)^2+q)\)
呃这个代码实现不太好写(我的码力问题
实现上的小细节
记得建的是反边,回答询问的时候记得特判两个点最开始是否已经重合.
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 255, M = 4e6+5, inf = 1e9;
int n,m,q,np;
struct point
{
int x,y;
void rd() { scanf("%d%d",&x,&y); }
void print() { printf("(%d,%d)",x,y); }
friend bool operator< (const point &a, const point &b) { return a.x<b.x or (a.x==b.x and a.y<b.y); }
friend bool operator== (const point &a, const point &b) {return a.x==b.x and a.y==b.y; }
friend point operator+ (const point &a, const point &b) { return {a.x+b.x,a.y+b.y}; }
friend point operator- (const point &a, const point &b) { return {a.x-b.x,a.y-b.y}; }
} p[N<<3];
int a[N][N][4],dis[M],mp[N][N];
inline int p_to_q(int x, int y) { return (x-1)*np+y; }
int head[M],nxt[M<<4],ver[M<<4],tot;
void add(int x, int y) { ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot; }
void init()
{
//init p
static point obs[N],dir[]={{1,0},{0,1},{-1,0},{0,-1}};
static int vt[N][N];
auto check=[&](point t) { return 1<=t.x and t.x<=n and 1<=t.y and t.y<=n and !vt[t.x][t.y]; };
for(int i=1; i<=m; i++) obs[i].rd(),vt[obs[i].x][obs[i].y]=1;
for(int i=1; i<=n; i++)
{
if(check({1,i})) p[++np]={1,i};
if(check({n,i})) p[++np]={n,i};
if(check({i,1})) p[++np]={i,1};
if(check({i,n})) p[++np]={i,n};
}
for(int i=1; i<=m; i++) for(int j=0; j<4; j++)
{
point t=obs[i]+dir[j];
if(check(t)) p[++np]=t;
}
sort(p+1,p+np+1); np=unique(p+1,p+np+1)-p-1;
for(int i=1; i<=np; i++) mp[p[i].x][p[i].y]=i;
//init a
for(int i=1; i<=n; i++) for(int j=1; j<=n; j++)
if(check({i,j})) for(int k=0; k<4; k++)
{
point c={i,j};
while(check(c+dir[k])) c=c+dir[k];
a[i][j][k]=mp[c.x][c.y];
}
//init q
for(int i=1; i<=np; i++) for(int j=1; j<=np; j++)
for(int k=0; k<4; k++)
{
int u=p_to_q(i,j);
int v=p_to_q(a[p[i].x][p[i].y][k],a[p[j].x][p[j].y][k]);
add(v,u);
}
}
void work_dist()
{
queue<int> q;
static int vis[M];
for(int i=1; i<=np*np; i++) dis[i]=inf;
for(int i=1; i<=np; i++) { int t=p_to_q(i,i); q.push(t); dis[t]=0; vis[t]=1; }
while(!q.empty())
{
int u=q.front(); q.pop();
for(int j=head[u]; j; j=nxt[j])
{
int v=ver[j];
if(!vis[v]) dis[v]=min(dis[v],dis[u]+1),vis[v]=1,q.push(v);
}
}
}
void answer_query()
{
point S,T;
while(q--)
{
S.rd(); T.rd(); int res=inf;
if(S==T) res=0;
else if(mp[S.x][S.y] and mp[T.x][T.y]) res=dis[p_to_q(mp[S.x][S.y],mp[T.x][T.y])];
else for(int j=0; j<4; j++) res=min(res,1+dis[p_to_q(a[S.x][S.y][j],a[T.x][T.y][j])]);
printf("%d\n",res>=inf?-1:res);
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
init(); work_dist(); answer_query();
return 0;
}
标签:const,point,int,P7473,d%,return,bfs,2021,洛谷
From: https://www.cnblogs.com/copper-carbonate/p/16882123.html