题解
- 题目大意:给定一个n*n的图,有n个可以转向的交点(横纵变化),每次转向需要1的代价,每走一个站需要2的代价,问从起点到终点的最小代价
- 显然,我们可以对于一个点拆成两个点(横纵),然后对于每个转向的点的横纵相连,代价为1
- 同行同列相连,代价为距离*2,起点和终点横纵转换可以不用代价,因为可以起点可以任意开始,终点也可以从上下到达
- 建完图就可以直接跑spfa(不怕被卡的话)
代码
1 #include <cstdio>
2 #include <queue>
3 #include <algorithm>
4 #define inf 0x7fffffff
5 #define N 200010
6 using namespace std;
7 struct node { int to,from,v; }E[N*4];
8 struct edge { int x,y,d; }e[N];
9 int n,m,cnt,head[N*4],dis[N],vis[N];
10 queue<int> Q;
11 bool cmp(edge a,edge b) { return (a.x==b.x)?a.y<b.y:a.x<b.x; }
12 bool CMP(edge a,edge b) { return (a.y==b.y)?a.x<b.x:a.y<b.y; }
13 void insert(int x,int y,int v)
14 {
15 E[++cnt].to=y,E[cnt].from=head[x],E[cnt].v=v,head[x]=cnt;
16 E[++cnt].to=x,E[cnt].from=head[y],E[cnt].v=v,head[y]=cnt;
17 }
18 int spfa()
19 {
20 for (int i=1;i<=(m+2)*2;i++) dis[i]=inf;
21 vis[m+1]=1,dis[m+1]=0,Q.push(m+1);
22 while (!Q.empty())
23 {
24 int u=Q.front(); Q.pop(),vis[u]=0;
25 for (int i=head[u];i;i=E[i].from)
26 if (dis[E[i].to]>dis[u]+E[i].v)
27 {
28 dis[E[i].to]=dis[u]+E[i].v;
29 if (!vis[E[i].to]) vis[E[i].to]=1,Q.push(E[i].to);
30 }
31 }
32 return dis[m+2]==inf?-1:dis[m+2];
33 }
34 int main()
35 {
36 scanf("%d%d",&n,&m);
37 for (int i=1;i<=m+2;i++) scanf("%d%d",&e[i].x,&e[i].y),e[i].d=i;
38 sort(e+1,e+m+2+1,cmp);
39 for (int i=1;i<m+2;i++) if (e[i].x==e[i+1].x) insert(e[i].d,e[i+1].d,2*(e[i+1].y-e[i].y));
40 sort(e+1,e+m+2+1,CMP);
41 for (int i=1;i<m+2;i++) if (e[i].y==e[i+1].y) insert(e[i].d+m+2,e[i+1].d+m+2,2*(e[i+1].x-e[i].x));
42 for (int i=1;i<=m;i++) insert(i,i+m+2,1);
43 insert(m+1,m+m+3,0),insert(m+2,(m+2)*2,0);
44 printf("%d",spfa());
45 }