循环队列+堆优化dijkstra最短路 BZOJ 4152: [AMPPZ2014]The Captain
循环队列基础知识
1.循环队列需要几个参数来确定
循环队列需要2个参数,front和rear
2.循环队列各个参数的含义
(1)队列初始化时,front和rear值都为零;
(2)当队列不为空时,front指向队列的第一个元素,rear指向队列最后一个元素的下一个位置;
(3)当队列为空时,front与rear的值相等,但不一定为零;
3.循环队列入队的伪算法
(1)把值存在rear所在的位置;
(2)rear=(rear+1)%maxsize ,其中maxsize代表数组的长度;
4.循环队列出队的伪算法
(1)先保存出队的值;
(2)front=(front+1)%maxsize ,其中maxsize代表数组的长度;
5.如何判断循环队列是否为空
if(front==rear)
队列空;
else
队列不空;
6.如何判断循环队列是否为满?
这个问题比较复杂,假设数组的存数空间为7,此时已经存放1,a,5,7,22,90六个元素了,如果在往数组中添加一个元素,则rear=front;此时,队列满与队列空的判断条件front=rear相同,这样的话我们就不能判断队列到底是空还是满了;
解决这个问题有两个办法:一是增加一个参数,用来记录数组中当前元素的个数;第二个办法是,少用一个存储空间,也就是数组的最后一个存数空间不用,当(rear+1)%maxsiz=front时,队列满;
例题:
4152: [AMPPZ2014]The Captain
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 664 Solved: 256
[Submit][Status][Discuss]
Description
给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用。
Input
第一行包含一个正整数n(2<=n<=200000),表示点数。
接下来n行,每行包含两个整数x[i],y[i](0<=x[i],y[i]<=10^9),依次表示每个点的坐标。
Output
一个整数,即最小费用。
Sample Input
5
2 2
1 1
4 5
7 1
6 7
2 2
1 1
4 5
7 1
6 7
Sample Output
2
首先,我们可以无视min,直接两点之间建一条|x2-x1|的边和一条|y2-y1|的边 可以发现,对于点(x1,y1),(x2,y2),(x3,y3),x1<x2<x3,则|x2-x1|+|x3-x2| = |x3-x1| 所以从x1连向x3用x坐标计算权值的边是没有用的。 Y同理 所以每个点只需要向上下左右最靠近的点连边,排序即可 先按x排序, 然后只有相邻节点的边才有用, 我们连起来, 再按y排序做相同操作...然后就跑dijikstra,这个题目是卡spfa的。
而且dijistra不用队优化会超时的。呵呵~。
1 #include<cstring> 2 #define N 200010 3 #define inf (unsigned long long)((1<<63)-1)/*直接复制(1<<63)-1是会出现-1的,在前面要有ull*/ 4 #include<iostream> 5 using namespace std; 6 #include<cstdio> 7 #include<cstdlib> 8 #include<queue> 9 #include<cmath> 10 #include<algorithm> 11 struct Edge{ 12 int v,last; 13 unsigned long long w; 14 }edge[N<<2]; 15 struct Jg{ 16 int x,y; 17 }dian[N]; 18 int head[N],X[N],Y[N],n,t=0; 19 unsigned long long dis[N]; 20 struct Dis{ 21 int id; 22 unsigned long long d; 23 Dis(){d=inf;} 24 bool operator <(Dis K) 25 const{return d>K.d; }/*优先队列是默认大的元素在前,这个重载运算符只能对<,把他变成>即可*/ 26 }; 27 priority_queue<Dis>Q; 28 bool vis[N]={false}; 29 inline int read() 30 { 31 int ret=0,ff=1; 32 char s=getchar(); 33 while(s<'0'||s>'9') 34 { 35 if(s=='-') ff=-1; 36 s=getchar(); 37 } 38 while(s>='0'&&s<='9') 39 { 40 ret=ret*10+s-'0'; 41 s=getchar(); 42 } 43 return ret*ff; 44 } 45 void input() 46 { 47 n=read(); 48 for(int i=1;i<=n;++i) 49 { 50 dian[i].x=read();dian[i].y=read(); 51 X[i]=Y[i]=i; 52 } 53 } 54 bool cmpx(int a,int b)/*排序,a,b代表X[N]数组中的某两个元素,他们代表的是dian数组的编号*/ 55 { 56 return dian[a].x<dian[b].x; 57 } 58 bool cmpy(int a,int b) 59 { 60 return dian[a].y<dian[b].y; 61 } 62 void add_edge(int a,int b,int falgg) 63 { 64 if(falgg==1) 65 { 66 ++t; 67 edge[t].v=b; 68 edge[t].w=abs(dian[a].x-dian[b].x); 69 edge[t].last=head[a]; 70 head[a]=t; 71 } 72 else 73 { 74 ++t; 75 edge[t].v=b; 76 edge[t].w=abs(dian[a].y-dian[b].y); 77 edge[t].last=head[a]; 78 head[a]=t; 79 } 80 } 81 void build_line() 82 {/*先按x排序, 然后只有相邻节点的边才有用, 我们连起来, 再按y排序做相同操作.*/ 83 sort(X+1,X+n+1,cmpx); 84 for(int i=2;i<=n;++i) 85 { 86 add_edge(X[i],X[i-1],1); 87 add_edge(X[i-1],X[i],1); 88 } 89 sort(Y+1,Y+n+1,cmpy); 90 for(int i=2;i<=n;++i) 91 { 92 add_edge(Y[i],Y[i-1],2); 93 add_edge(Y[i-1],Y[i],2); 94 } 95 } 96 void dijkstra() 97 { 98 for(int i=1;i<=n;++i) 99 dis[i]=inf; 100 dis[1]=0; 101 Dis now; 102 now.id=1;now.d=0; 103 Q.push(now); 104 while(!Q.empty()) 105 { 106 Dis nowe=Q.top(); 107 Q.pop(); 108 if(dis[nowe.id]!=nowe.d)continue; 109 if(vis[nowe.id])continue; 110 vis[nowe.id]=true; 111 for(int l=head[nowe.id];l;l=edge[l].last) 112 { 113 if(!vis[edge[l].v]&&dis[edge[l].v]>dis[nowe.id]+edge[l].w) 114 { 115 dis[edge[l].v]=dis[nowe.id]+edge[l].w; 116 Dis now; 117 now.id=edge[l].v;now.d=dis[edge[l].v]; 118 Q.push(now); 119 } 120 } 121 } 122 } 123 int main() 124 { 125 input(); 126 build_line(); 127 dijkstra(); 128 cout<<dis[n]; 129 return 0; 130 }