先附上一个例题:P3371 【模板】单源最短路径
一眼扫去,最短路。。。
spfa可行,但是今天的主题是Dijkstra:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 10010 #define MAXM 500010 #define MAX 999999999 using namespace std; int n,m,s,c=1; int head[MAXN],path[MAXN]; bool vis[MAXN]; struct node{ int next,to,w; }a[MAXM<<1]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline void add(int u,int v,int w){ a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++; } void dijkstra(){ for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;} path[s]=0; for(int i=1,k,v;i<=n;i++){ k=-1; for(int j=1;j<=n;j++)if(!vis[j]&&(k==-1||path[k]>path[j]))k=j; if(k==-1)break; vis[k]=true; for(int j=head[k];j;j=a[j].next){ v=a[j].to; if(!vis[v]&&path[v]>path[k]+a[j].w)path[v]=path[k]+a[j].w; } } for(int i=1;i<=n;i++)printf("%d ",path[i]==MAX?2147483647:path[i]); printf(" "); } int main(){ int u,v,w; n=read();m=read();s=read(); for(int i=1;i<=m;i++){ u=read();v=read();w=read(); add(u,v,w); } dijkstra(); return 0; }
然而,遇上某些题,n<=100,000,怎么办?
这时候,堆优化就出场了。
堆优化:
堆优化,即用堆来实现O( log2n )时间内找到到起点最短的未被松弛的点。
当然,你需要自定义结构体。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<queue> #define MAXN 10010 #define MAXM 500010 #define MAX 999999999 using namespace std; int n,m,s,c=1; int head[MAXN],path[MAXN]; bool vis[MAXN]; struct node{ int next,to,w; }a[MAXM]; struct Point{ int x,dis; bool operator <(const Point &p)const{ return dis>p.dis; } }; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline void add(int u,int v,int w){ a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++; } void dijkstra(){ Point u,v; priority_queue<Point> q; for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;} u.x=s;u.dis=path[s]=0; q.push(u); while(!q.empty()){ u=q.top(); q.pop(); if(!vis[u.x]){ vis[u.x]=true; for(int i=head[u.x];i;i=a[i].next){ v.x=a[i].to; if(!vis[v.x]){ path[v.x]=min(path[v.x],path[u.x]+a[i].w); v.dis=u.dis+a[i].w; q.push(v); } } } } for(int i=1;i<=n;i++)printf("%d ",path[i]==MAX?2147483647:path[i]); printf(" "); } int main(){ int u,v,w; n=read();m=read();s=read(); for(int i=1;i<=m;i++){ u=read();v=read();w=read(); add(u,v,w); } dijkstra(); return 0; }
不得不说,这玩意效率虽然没有spfa+SLF高,但是遇上了这题,你也是无可奈何地用它:
后记:
附上洛谷上的两次提交:(P3371)
朴素Dijkstra:Accepted 100
1036ms / 7.77MB
代码:1.11KB C++
Dijkstra+堆优化:Accepted 100
348ms / 9.49MB
代码:1.3KB C++
明显快了不少。
不过出题人没事干也不会卡你的spfa,至少在NOIP这种考试中。。。