循环队列
循环队列
队列:先进先出,FIFO。
牺牲一个单元,使队列为空和只有一个元素时不要产生歧义
队首front,队尾rear,队列为a[front+1]~a[rear]
开一个大小为n的数组,a:array[0..n-1] of longint ,当rear=n-1时,需要在队尾增加一个数据,此时没有存储空间,但此时使用的内存单元只是a[front+1]~a[rear],前面的a[1]~a[front]内存单元未被使用,却没有存储空间,导致假溢出。
可以使用循环队列,当rear=n-1,增加一个数据,则rear变为0,即回到原点。相当于把数组看成一个圆,设置圆的开头和结尾(相邻),从开头到结尾存储数据,当到了结尾,又重新返回开头。
Spfa常使用循环队列,从而节省队列的内存。
注意:
1.在队列里的点都不重复,所以队列的长度小于等于n(点的总个数)+1(牺牲的一个单元),
2.不用判断队列大小单元不够,只要开的足够大即可
ccf20170304类似spfa:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <malloc.h> 4 #include <stdbool.h> 5 #define maxn 100000 6 #define maxm 200000 7 #define maxc 1000000 8 9 long max(long a,long b) 10 { 11 if (a>b) 12 return a; 13 else 14 return b; 15 } 16 17 int main() 18 { 19 struct node 20 { 21 long d,len; 22 struct node *next; 23 }; 24 long n,m,head,tail,d,value,i,a,b,c; 25 long *dis=(long *) malloc (sizeof(long)*(maxn+1)); 26 //循环队列 27 long *line=(long *) malloc (sizeof(long)*(maxn+1)); 28 bool *vis=(bool *) malloc (sizeof(bool)*(maxn+1)); 29 //本身已经是struct node *point,创建数组再加"*" 30 struct node **point=(struct node **) malloc (sizeof(struct node *)*(maxn+1)); 31 struct node *t; 32 scanf("%ld%ld",&n,&m); 33 34 for (i=1;i<=n;i++) 35 { 36 point[i]=NULL; 37 //1 ≤ c ≤ 1000000 38 //max<=c 39 dis[i]=maxc; 40 vis[i]=true; 41 } 42 for (i=1;i<=m;i++) 43 { 44 scanf("%ld%ld%ld",&a,&b,&c); 45 //build a 46 t=(struct node *) malloc (sizeof(struct node)); 47 t->d=b; 48 t->len=c; 49 if (point[a]!=NULL) 50 t->next=point[a]; 51 else 52 t->next=NULL; 53 point[a]=t; 54 //build b 55 t=(struct node *) malloc (sizeof(struct node)); 56 t->d=a; 57 t->len=c; 58 if (point[b]!=NULL) 59 t->next=point[b]; 60 else 61 t->next=NULL; 62 point[b]=t; 63 } 64 dis[1]=0; 65 vis[1]=false; 66 line[1]=1; 67 //head=front-1 牺牲一个位置 front为队列头位置 68 head=0; 69 tail=1; 70 //这里的循环队列不用判断空或者溢出 71 //因为如果那样的话,已经不能用了。 72 //不存在空的情况。而数组要开的足够大,使队列不溢出。 73 while (head!=tail) 74 { 75 //head++; 76 //队列为0~n 77 head++; 78 if (head==n+1) 79 head=0; 80 d=line[head]; 81 t=point[d]; 82 while (t) 83 { 84 if (dis[d]<t->len) 85 value=t->len; 86 else 87 value=dis[d]; 88 if (value<dis[t->d]) 89 { 90 dis[t->d]=value; 91 //如果该点未被放在队列里,则入队;否则不入队 92 //即在队列里的点都不重复 93 //则队列(tail-head)最多有n+1个数(n个点+空位置(head)) 94 if (vis[t->d]) 95 { 96 //tail++; 97 tail++; 98 if (tail==n+1) 99 tail=0; 100 line[tail]=t->d; 101 vis[t->d]=false; 102 } 103 } 104 t=t->next; 105 } 106 vis[d]=true; 107 } 108 printf("%ld\n",dis[n]); 109 return 0; 110 }
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <malloc.h> 4 #include <stdbool.h> 5 #define maxn 100000 6 #define maxm 200000 7 #define maxc 1000000 8 9 long max(long a,long b) 10 { 11 if (a>b) 12 return a; 13 else 14 return b; 15 } 16 17 int main() 18 { 19 struct node 20 { 21 long d,len; 22 struct node *next; 23 }; 24 long n,m,head,tail,d,value,i,a,b,c; 25 long *dis=(long *) malloc (sizeof(long)*(maxn+1)); 26 //循环队列 27 long *line=(long *) malloc (sizeof(long)*(maxn+1)); 28 bool *vis=(bool *) malloc (sizeof(bool)*(maxn+1)); 29 //本身已经是struct node *point,创建数组再加"*" 30 struct node **point=(struct node **) malloc (sizeof(struct node *)*(maxn+1)); 31 struct node *t; 32 scanf("%ld%ld",&n,&m); 33 34 for (i=1;i<=n;i++) 35 { 36 point[i]=NULL; 37 //1 ≤ c ≤ 1000000 38 //max<=c 39 dis[i]=maxc; 40 vis[i]=true; 41 } 42 for (i=1;i<=m;i++) 43 { 44 scanf("%ld%ld%ld",&a,&b,&c); 45 //build a 46 t=(struct node *) malloc (sizeof(struct node)); 47 t->d=b; 48 t->len=c; 49 if (point[a]!=NULL) 50 t->next=point[a]; 51 else 52 t->next=NULL; 53 point[a]=t; 54 //build b 55 t=(struct node *) malloc (sizeof(struct node)); 56 t->d=a; 57 t->len=c; 58 if (point[b]!=NULL) 59 t->next=point[b]; 60 else 61 t->next=NULL; 62 point[b]=t; 63 } 64 dis[1]=0; 65 vis[1]=false; 66 line[1]=1; 67 //head=front-1 牺牲一个位置 front为队列头位置 68 head=0; 69 tail=1; 70 //这里的循环队列不用判断空或者溢出 71 //因为如果那样的话,已经不能用了。 72 //不存在空的情况。而数组要开的足够大,使队列不溢出。 73 while (head!=tail) 74 { 75 //head++; 76 //队列为0~n 77 head++; 78 if (head==n+1) 79 head=0; 80 d=line[head]; 81 t=point[d]; 82 while (t) 83 { 84 if (dis[d]<t->len) 85 value=t->len; 86 else 87 value=dis[d]; 88 if (value<dis[t->d]) 89 { 90 dis[t->d]=value; 91 //如果该点未被放在队列里,则入队;否则不入队 92 //即在队列里的点都不重复 93 //则队列(tail-head)最多有n+1个数(n个点+空位置(head)) 94 if (vis[t->d]) 95 { 96 //tail++; 97 tail++; 98 if (tail==n+1) 99 tail=0; 100 line[tail]=t->d; 101 vis[t->d]=false; 102 } 103 } 104 t=t->next; 105 } 106 vis[d]=true; 107 } 108 printf("%ld\n",dis[n]); 109 return 0; 110 }