版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/86611809
正题
luogu评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P3831
题目大意
有 的铁路网走一格代价为2, 个中转站可以改变方向代价为1。求两个点之间的最短路。
解题思路
我们发现 很大,所以我们考虑根据 建图。算上起点和终点为中转站。
对于每个中转站,我们只连接上下左右最近的点,这个排序可以做到。这样边数就不会太多。可是如何解决转向的问题。
对于每个点,拆成横点和纵点,横着的连横点,竖着的连纵点,横点和纵点之间建立一条边,长度为1。
问题完美解决
#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#define py(aaa) aaa*2-1
#define px(aaa) aaa*2
using namespace std;
const int N=200100,L=20010;
struct node{
int to,next,w;
}a[N*5];
vector<int> in_x[L],in_y[L];
queue<int> q;
int ls[N],tot,n,m,f[N],v[N],x[N],y[N];
bool cmp_x(int xs,int ys)
{return y[xs]<y[ys];}
bool cmp_y(int xs,int ys)
{return x[xs]<x[ys];}
void addl(int x,int y,int w)
{
a[++tot].to=y;a[tot].w=w;
a[tot].next=ls[x];ls[x]=tot;
}
int spfa(int s,int t)
{
memset(f,0x3f,sizeof(f));
f[py(s)]=f[px(s)]=0;
q.push(py(s));q.push(px(s));
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=ls[x];i;i=a[i].next)
{
int y=a[i].to;
if(f[x]+a[i].w<f[y]){
f[y]=f[x]+a[i].w;
if(!v[y]){
q.push(y);
v[y]=true;
}
}
}
v[x]=false;
}
if(f[px(t)]>=1061109567) return -1;
return min(f[px(t)],f[py(t)]);
}
int main()
{
scanf("%d%d",&n,&m);
m+=2;
for(int i=1;i<=m;i++){
scanf("%d%d",&x[i],&y[i]);
in_x[x[i]].push_back(i);in_y[y[i]].push_back(i);
addl(px(i),py(i),1);addl(py(i),px(i),1);
}
for(int i=1;i<=n;i++)
sort(in_x[i].begin(),in_x[i].end(),cmp_x);
for(int k=1;k<=n;k++)
for(int i=0;i+1<in_x[k].size();i++)
{
int as=in_x[k][i],bs=in_x[k][i+1];
addl(px(as),px(bs),(y[bs]-y[as])*2);
addl(px(bs),px(as),(y[bs]-y[as])*2);
}
for(int i=1;i<=n;i++)
sort(in_y[i].begin(),in_y[i].end(),cmp_y);
for(int k=1;k<=n;k++)
for(int i=0;i+1<in_y[k].size();i++)
{
int as=in_y[k][i],bs=in_y[k][i+1];
addl(py(as),py(bs),(x[bs]-x[as])*2);
addl(py(bs),py(as),(x[bs]-x[as])*2);
}
printf("%d",spfa(m-1,m));
}