Dijkstra--The Captain
给定平面上的n个点,定义$(x_1,y_1)$到$(x_2,y_2)$的费用为min(|$x_1$-$x_2$|,|$y_1$-$y_2$|),求从1号点走到n号点的最小费用。
先给一段证明:给定三个x值,$x_1<x_2<x_3$。可得$x_2-x_1<x_3-x_2<x_3-x_1$,对于最小费用,很明显只有$x_2-x_1$是有用的。对y同理,同时要注意我们不能把$x$和$y$两者混谈。由此我们得到了一个思路,分层图x和y跑一次最短路。
首先两个$cmp$函数对$n$个点进行的两次排序(注意在之前把点的序号也存下来):
1 bool cmp1(node a,node b) 2 { 3 return a.x<b.x; 4 } 5 bool cmp2(node a,node b) 6 { 7 return a.y<b.y; 8 }
链式前向星构图:
1 struct edge 2 { 3 int next,to,w; 4 }edge[maxn]; 5 void add(int u,int v,int w) 6 { 7 edge[++tot].w=w; 8 edge[tot].to=v; 9 edge[tot].next=head[u]; 10 head[u]=tot; 11 } 12 sort(a+1,a+n+1,cmp1); 13 for (int i = 1;i < n;i++) 14 { 15 add(a[i].id,a[i+1].id,abs(a[i].x-a[i+1].x)); 16 add(a[i+1].id,a[i].id,abs(a[i].x-a[i+1].x)); 17 } 18 sort(a+1,a+n+1,cmp2); 19 for (int i = 1;i < n;i++) 20 { 21 add(a[i].id,a[i+1].id,abs(a[i].y-a[i+1].y)); 22 add(a[i+1].id,a[i].id,abs(a[i].y-a[i+1].y)); 23 }
然后是很标准的dij板子:
1 void Dijkstra(int S) 2 { 3 q.push(make_pair(0,S)); memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); dis[S] = 0; 4 while(!q.empty()) 5 { 6 int x = q.top().second; 7 q.pop(); 8 if(vis[x]) 9 continue; 10 vis[x] = 1; 11 for(int i=head[x];i!=0;i=edge[i].next) 12 { 13 int to1=edge[i].to; 14 if(dis[to1] > dis[x] + edge[i].w) 15 { 16 dis[to1] = dis[x] + edge[i].w ; 17 q.push(make_pair(-dis[to1],to1)); 18 } 19 } 20 } 21 return; 22 }
完整代码如下:
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <queue> 6 #include <cmath> 7 using namespace std; 8 #define ll long long 9 int n; 10 const int maxn=1000000; 11 priority_queue< pair<int ,int > >q; 12 int dis[maxn],vis[maxn]; 13 int tot=0,head[maxn]; 14 int read(){ 15 int x=1,a=0; 16 char ch=getchar(); 17 while (ch < '0'||ch > '9'){ 18 if (ch == '-') x=-1; 19 ch = getchar(); 20 } 21 while (ch <= '9'&&ch >= '0') 22 { 23 a = a*10 + ch- '0'; 24 ch=getchar(); 25 } 26 return x*a; 27 } 28 struct node 29 { 30 int x,y,id; 31 }a[maxn]; 32 struct edge 33 { 34 int next,to,w; 35 }edge[maxn]; 36 void add(int u,int v,int w) 37 { 38 edge[++tot].w=w; 39 edge[tot].to=v; 40 edge[tot].next=head[u]; 41 head[u]=tot; 42 } 43 bool cmp1(node a,node b) 44 { 45 return a.x<b.x; 46 } 47 bool cmp2(node a,node b) 48 { 49 return a.y<b.y; 50 } 51 void Dijkstra(int S) 52 { 53 q.push(make_pair(0,S)); memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); dis[S] = 0; 54 while(!q.empty()) 55 { 56 int x = q.top().second; 57 q.pop(); 58 if(vis[x]) 59 continue; 60 vis[x] = 1; 61 for(int i=head[x];i!=0;i=edge[i].next) 62 { 63 int to1=edge[i].to; 64 if(dis[to1] > dis[x] + edge[i].w) 65 { 66 dis[to1] = dis[x] + edge[i].w ; 67 q.push(make_pair(-dis[to1],to1)); 68 } 69 } 70 } 71 return; 72 } 73 int main() 74 { 75 n=read(); 76 for (int i = 1;i <= n;i++) 77 { 78 a[i].x=read(),a[i].y=read(); 79 a[i].id=i; 80 } 81 sort(a+1,a+n+1,cmp1); 82 for (int i = 1;i < n;i++) 83 { 84 add(a[i].id,a[i+1].id,abs(a[i].x-a[i+1].x)); 85 add(a[i+1].id,a[i].id,abs(a[i].x-a[i+1].x)); 86 } 87 sort(a+1,a+n+1,cmp2); 88 for (int i = 1;i < n;i++) 89 { 90 add(a[i].id,a[i+1].id,abs(a[i].y-a[i+1].y)); 91 add(a[i+1].id,a[i].id,abs(a[i].y-a[i+1].y)); 92 } 93 Dijkstra(1); 94 cout<<dis[n]; 95 return 0; 96 }