单源最短路dijkstra算法&&优化史
一下午都在学最短路dijkstra算法,总算是优化到了我能达到的水平的最快水准,然后列举一下我的优化历史,顺便总结总结
最朴素算法:
邻接矩阵存边+贪心||dp思想,几乎纯暴力,luoguTLE+MLE,
算优点??:但好写好想,比下面的代码短了差不多一半。
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; int main() { int a[100][100],point,i,j,k,number,t1,t2,t3,u,n,min,book[10]={0},dis[10]; int inf=99999999; scanf("%d %d\n",&point,&number); int x; cin>>x; for(int i=1;i<=point;i++) for(int j=1;j<=point;j++) if(i==j)a[i][j]=0; else a[i][j]=inf; for(int i=1;i<=number;i++) { cin>>t1>>t2>>t3; a[t1][t2]=t3; } for(int i=1;i<=point;i++) dis[i]=a[1][i]; for(int i=1;i<=point-1;i++) { min=inf; for(int j=1;j<=point;j++) if(book[j]==0&& dis[j]<min) { min=dis[j]; u=j; } book[u]=1; for(int k=1;k<=point;k++) { if(a[u][k]<inf) if(dis[k]>dis[u]+a[u][k]) dis[k]=dis[u]+a[u][k]; } } for(int i=1;i<=point;i++) cout<<i<<" "<<dis[i]<<endl; return 0; }
第一次优化是前向星存边,
比上面最朴素的大量省空间,也省了部分时间,luogu上共用时1400ms+,一个点max接近五百。
1 #include<iostream> 2 #include <algorithm> 3 #include <string> 4 #include <cmath> 5 #include <cstring> 6 # include <cstdio> 7 #define maxi 2147483647; 8 9 using namespace std; 10 11 struct node 12 { 13 int z;//子节点 14 int val;//权值 15 int nexty;//最近父节点相同边编号 16 }edge[1000000]; 17 int head[20000];//某点为父节点运出的最后一条边 18 int cnt=0,curr;// 边id 19 20 inline void add(int a,int b,int c)//建立边向前星 21 { 22 cnt++; 23 edge[cnt].z=b; 24 edge[cnt].val =c; 25 edge[cnt].nexty =head[a]; 26 head[a]=cnt; 27 } 28 29 int main() 30 { 31 bool visit[20001]={0};//是否已经加入最短路 32 long long dis[20001];//最短路存值 33 int n,m,s; 34 int a,b,c; 35 36 scanf("%d%d%d",&n,&m,&s); 37 for(int i=1;i<=n;i++)//初始化边权值为无穷 38 dis[i]=maxi; 39 for(int i=0;i<m;i++) 40 { 41 scanf("%d%d%d",&a,&b,&c); 42 add(a,b,c); 43 } 44 //读入 45 curr=s; 46 dis[s]=0;//到最初点距离为零 47 long long minn; 48 49 while(!visit[curr]) 50 { 51 visit[curr]=true; 52 for(int i=head[curr];i!=0;i=edge[i].nexty ) 53 { 54 if(!visit[edge[i].z]&&dis[edge[i].z]>dis[curr]+edge[i].val ) 55 dis[edge[i].z]=dis[curr]+edge[i].val; 56 } 57 minn=2147483647; 58 for (int i=1;i<=n;i++) 59 if(!visit[i]&&minn>dis[i]) 60 { 61 minn=dis[i]; 62 curr=i; 63 } 64 } 65 for (int i=1;i<=n;i++) 66 printf("%lld ",dis[i]); 67 return 0; 68 }
最后的优化使代码长达近百行
主要运用:快读快写,优先队列(堆),前向星存边
不过这次优化使用结构体存边的时候发生了玄学错误,现在还是找不出错,不过用几个数组存边就AC了???
个人是喜欢结构体的,毕竟好写也整齐,但是没通过的话就不发出来了
这个复杂度又比上一个程序降低了不少,luogu 共用时500+ms,单个点max160+ms,比上一个快了大概3,4倍
下面这个是ac的数组存边。
1 #include <iostream> 2 #include <cstdio> 3 #include <queue> 4 #include <algorithm> 5 #include <vector> 6 #include <stdio.h> 7 #include <string.h> 8 #define maxn 10005 9 #define maxm 500005 10 #define inf 2147483647 11 12 using namespace std; 13 14 int n,m,cnt=0; 15 bool visit[maxn]; 16 int head[maxm],next[maxm],v[maxm],w[maxm],dist[maxn]; 17 18 inline int read() 19 { 20 char ch; 21 int a=0; 22 while(!(((ch=getchar())>='0')&&(ch<='9'))); 23 a*=10;a+=ch-'0'; 24 while(((ch=getchar())>='0')&&(ch<='9'))a*=10,a+=ch-'0'; 25 return a; 26 } 27 28 void write(int x) 29 { 30 if(x<0) putchar('-'),x=-x; 31 if(x>9)write(x/10); 32 putchar(x%10+'0'); 33 return ; 34 } 35 36 struct cmp 37 { 38 bool operator()(int x,int y) 39 { 40 return dist[x]>dist[y]; 41 } 42 }; 43 44 void add(int a,int b,int c) 45 { 46 v[cnt]=b; 47 w[cnt]=c; 48 next[cnt]=head[a]; 49 head[a]=cnt++; 50 return ; 51 } 52 53 void dijk(int s) 54 { 55 priority_queue<int,vector<int>,cmp> q2; 56 while(!q2.empty() ) 57 q2.pop() ; 58 dist[s]=0; 59 q2.push(s); 60 while(!q2.empty() ) 61 { 62 int x=q2.top() ; 63 q2.pop() ; 64 if(!visit[x]) 65 { 66 visit[x]=true; 67 for(int i=head[x];i!=-1;i=next[i]) 68 { 69 int y=v[i]; 70 dist[y]=min(dist[y],dist[x]+w[i]); 71 q2.push(y); 72 } 73 } 74 } 75 return ; 76 } 77 78 int main() 79 { 80 int s; 81 n=read(); 82 m=read(); 83 s=read(); 84 memset(head,-1,sizeof(head)); 85 memset(visit,0,sizeof(visit)); 86 for(int i=1;i<=m;i++) 87 { 88 int a,b,c; 89 a=read(),b=read(),c=read(); 90 add(a,b,c); 91 } 92 for(int i=1;i<=n;i++) 93 dist[i]=inf; 94 dijk(s); 95 for(int i=1;i<=n;i++) 96 write(dist[i]),putchar(' '); 97 return 0; 98 }
注意!这不是最优化dijkstra,只是个人能力能达到的最优化了。。。
写那么长的代码还是挺有成就感的
————————————————————————————————
执笔饰年华,一笑叹天涯。逢春即润物,生当得潇洒。