对于同一行和同一列的相邻的点分别建边。对行和列分层。建长度为1的边,之后SPFA即可。具体细节看代码。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
queue<int> q;
struct point
{
int x;
int y;
int id;
}a[100005];
int s,t;
struct node
{
int from;
int to;
int nxt;
int w;
}edge[2000005];
int tot;int head[500005],dis[500005];bool vis[500005];
void add(int u,int v,int w)
{
edge[tot].from=u;
edge[tot].to=v;
edge[tot].nxt=head[u];
edge[tot].w=w;
head[u]=tot++;
}
int sx,sy,tx,ty;
int cmp1(point x,point y)
{
if(x.x!=y.x)
return x.x<y.x;
return x.y<y.y;
}
int cmp2(point x,point y)
{
if(x.y!=y.y)
return x.y<y.y;
return x.x<y.x;
}
void spfa(int x)
{
q.push(x);
dis[x]=0;
while(!q.empty())
{
x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i!=-1;i=edge[i].nxt)
{
if(dis[edge[i].to]>dis[x]+edge[i].w)
{
dis[edge[i].to]=dis[x]+edge[i].w;
if(!vis[edge[i].to])
{q.push(edge[i].to);
vis[edge[i].to]=1;
}
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
int n,m;
cin>>n>>m;
for(int i=1;i<=m+2;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
a[i].id=i;
if(i<=m)
{
add(i,i+m+2,1);//分层建边
add(i+m+2,i,1);
}
else
{
add(i,i+m+2,0);
add(i+m+2,i,0);//处理起点和终点
}
}
s=a[m+1].id;t=a[m+2].id;
sort(a+1,a+m+3,cmp1);
for(int i=1;i<=m+1;i++)
{
if(a[i].x==a[i+1].x)
{
add(a[i].id,a[i+1].id,2*(a[i+1].y-a[i].y));
add(a[i+1].id,a[i].id,2*(a[i+1].y-a[i].y));
}
}
sort(a+1,a+m+3,cmp2);
for(int i=1;i<=m+1;i++)
{
if(a[i].y==a[i+1].y)
{
add(m+a[i].id+2,m+a[i+1].id+2,2*(a[i+1].x-a[i].x));
//cout<<2*(a[i+1].x-a[i].x);
add(m+a[i+1].id+2,m+a[i].id+2,2*(a[i+1].x-a[i].x));
}
}
memset(dis,0x7f7f7f7f,sizeof(dis));
spfa(s);
if(dis[t]==0x7f7f7f7f)
printf("-1");
else printf("%d",dis[t]);
}