[spfa] Jzoj P3086 回家
题解
- 题目大意:给定一个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 }