\(By:Soroak\)
說到最短路問題,咱們無非就是用三種算法進行處理:
①: \(Floyd\) 。②: \(Dijkstra\) 。③: \(Spfa\)
對於最短路算法,學長以前給咱們講過,但是當時我由於不想聽課,上課走神等緣由,成功的沒有學紮實,如今來從新 複習 從新學習一下c++
如下是 \(Floyd\) 的模板:git
#include<iostream> #include<cstdio> #include<cstring> #define int long long int using namespace std; int map[5010][5010]; int n,m; const int INF=0x7fffffff; signed main() { cin>>n>>m; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { map[i][j]=INF; } } for(int i=1;i<=n;i++) { map[i][i]=0; } for(int i=1;i<=m;i++) { int u,v,w; cin>>u>>v>>w; map[u][v]=w; map[v][u]=w; } for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(map[i][j]>map[i][k]+map[k][j]&&k!=i&&k!=j&&i!=j) { map[i][j]=map[i][k]+map[k][j]; } } } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cout<<map[i][j]<<" "; } cout<<endl; } return 0; } /*樣例輸入 4 6 1 2 2 2 3 2 2 4 1 1 3 5 3 4 3 1 4 4 輸出: 0 2 4 3 2 0 2 1 4 2 0 3 3 1 3 0 *、
定義: \(Dijkstra\) 算法是典型的單源最短路徑算法,用於計算一個節點到其餘全部節點的最短路徑。主要特色是以起始點爲中心向外層層擴展,直到擴展到終點爲止。算法
Q&A:
Q: \(Dijkstra\) 比 \(Floyd\) 好在哪裏呢??
A:上面說過 \(Dijkstra\) 是典型的單源最短路徑算法,何謂單源最短路??就是給定一個起始點,求這個點到全部點的最短路,求一遍 \(Dijkstra\) (非優化)的時間複雜度是 \(O(N^2)\) ,你要是想求出每一個點到每一個點的最短路,我仍是建議你用 \(Floyd\) ,由於 \(Dijkstra\) 求 \(N\) 遍單源最短路的複雜度和 \(Floyd\) 同樣都是 \(O(N^3)\) ,固然,這裏說的都是未優化的狀況,優化的 \(Dijkstra\) 下面會講到。閉包
\(Dijkstra\) 從隨意一個點出發,到達各點的最短路徑長度的代碼以下:學習
//#include<iostream> //#include<cstdio> //#include<cstring> //#define int long long int // //using namespace std; // //int map[5010][5010]; //int dis[5010]; //int fl[5010]; //int n,m,s; //const int inf=2147483647; // //inline void dijkstra(int u) //{ // memset(dis,63,sizeof(dis)); // int start=u; // fl[start]=1; // for(int i=1;i<=n;i++) // { // dis[i]=min(dis[i],map[start][i]); // } // for(int i=1;i<=n-1;i++) // { // int minn=inf; // for(int j=1;j<=n;j++) // { // if(fl[j]==0&&minn>dis[j]) // { // minn=dis[j]; // start=j; // } // } // fl[start]=1; // for(int j=1;j<=n;j++) // { // dis[j]=min(dis[j],dis[start]+map[start][j]); // } // } //} // //signed main() //{ // cin>>n>>m>>s; // memset(map,63,sizeof(map)); // for(int i=1;i<=m;i++) // { // int a,b,c; // cin>>a>>b>>c; // map[a][b]=c; // map[b][a]=c; // } // for(int i=1;i<=n;i++) // { // map[i][i]=0; // } // dijkstra(s); // for(int i=1;i<=n;i++) // { // cout<<dis[i]<<" "; // } // return 0; //} #include<iostream> #include<cstdio> #include<cstring> #define int long long int using namespace std; int value[10010]; int to[10010]; int nxt[10010]; int head[10010]; int total; int fl[10010]; int dis[10010]; int n,m,s; inline void add(int a,int b,int c) { total++; to[total]=b; value[total]=c; nxt[total]=head[a]; head[a]=total; } void dijkstra(int u) { memset(dis,63,sizeof(dis)); memset(fl,0,sizeof(fl)); dis[u]=0; for(int i=1;i<n;i++) { int start=-1; for(int j=1;j<=n;j++) { if(fl[j]==0&&(dis[start]>dis[j]||start==-1)) { start=j; } } fl[start]=1; for(int e=head[start];e;e=nxt[e]) { dis[to[e]]=min(dis[to[e]],dis[start]+value[e]); } } } signed main() { cin>>n>>m>>s; for(int i=1;i<=m;i++) { int a,b,c; cin>>a>>b>>c; add(a,b,c); add(b,a,c); } dijkstra(s); for(int i=1;i<=n;i++) { cout<<dis[i]<<" "; } cout<<endl; return 0; }
下面上代碼:
(感謝gyh大佬的大力支持)優化
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> const int INF=2147483647; const int MARX=1e5+10; using namespace std; struct edge { int u,v,w,ne; }e[MARX<<1]; struct p { int num,diss; bool operator<(const p &a)const { return diss>a.diss; } }tmp; int head[MARX],dis[MARX]; bool f[MARX]; int num,n,m,s,x; void add(int u,int v,int w) { e[++num].ne=head[u]; head[u]=num; e[num].u=u; e[num].v=v; e[num].w=w; } void dj(int s) { priority_queue <p> q; tmp.num=s; tmp.diss=0; q.push(tmp); for(int i=1;i<=n;i++) { dis[i]=INF; } dis[s]=0; while(!q.empty()) { int top=q.top().num; q.pop(); if(f[top]) { continue; } f[top]=1; for(int j=head[top];j;j=e[j].ne)//找k點的臨點,並進行比較 { if(dis[e[j].v] > dis[top]+e[j].w && (!f[e[j].v])) { dis[e[j].v] = dis[top]+e[j].w; tmp.num=e[j].v; tmp.diss=dis[e[j].v]; q.push(tmp); } } } } signed main() { scanf("%d%d%d",&n,&m,&s); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } dj(s); for(int i=1;i<=n;i++) { printf("%d ",dis[i]); } return 0; } /* // By:Luckyblock 使用STL中的 pair類實現 簡單好寫 #include<cstdio> #include<cstring> #include<ctype.h> #include<queue> #define int long long const int MARX = 2e6+10; //============================================================= struct edge { int u,v,w,ne; }e[MARX<<1]; int n,m,num, head[MARX]; int dis[MARX]; bool vis[MARX]; //============================================================= inline int read() { int s=1, w=0; char ch=getchar(); for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1; for(; isdigit(ch);ch=getchar()) w = w*10+ch-'0'; return s*w; } void add(int u,int v,int w) { e[++num].u = u,e[num].v = v, e[num].w = w; e[num].ne = head[u], head[u] = num; } void dijkstra(int start) { std::priority_queue <std::pair<int,int> > q; memset(dis,63,sizeof(dis)); dis[start] = 0 ; q.push(std::make_pair(0,start)); for(; !q.empty(); ) { std::pair <int,int> top = q.top(); q.pop(); if(vis[top.second]) continue; vis[top.second] = 1; for(int i=head[top.second]; i; i = e[i].ne) if(dis[e[i].v] > dis[e[i].u] + e[i].w) { dis[e[i].v] = dis[e[i].u] + e[i].w; q.push(std::make_pair(-dis[e[i].v], e[i].v)); } } } //============================================================= signed main() { n = read(), m = read(); int s = read(); for(int i=1; i<=m; i++) { int u = read(), v = read(), w = read(); add(u,v,w); } dijkstra(s); for(int i=1; i<=n; i++) printf("%lld ",dis[i]); } */
\(SPFA\) 代碼以及優化:(在這裏再次感謝gyh大佬的支持)ui
#include<cstdio> #include<queue> #define INF 2147483647 using namespace std; queue<int>q; struct edg { int u,v,next; int w; } edge[5000500]; int head[3000000]; int ans[3000000],vis[3000000]; int num=0; int s,t; void build(int u,int v,int w) { edge[++num].next=head[u]; head[u]=num; edge[num].u=u; edge[num].v=v; edge[num].w=w; } void SPFA(int s) { ans[s]=0; vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i;i=edge[i].next) { int v=edge[i].v; if(ans[v]>edge[i].w+ans[u]) { ans[v]=edge[i].w+ans[u]; if(!vis[v]) { q.push(v); vis[v]=1; } } } } } int main() { int n,m,s; scanf("%d%d%d",&n,&m,&s); for(int i=1; i<=n; i++) ans[i]=INF; for(int i=1; i<=m; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); build(a,b,c); } SPFA(s); for(int i=1; i<=n; i++) printf("%d ",ans[i]); return 0; } //==========簡單好用優先隊列優化========== //優化很成功,時間複雜度較低,吊打DJ BOBO /* //將queue改成priority_queue,注意將q.front()改成q.top() //同時自定義優先級 , 以最短路徑長度升序排列 #include<cstdio> #include<queue> #define INF 2147483647 using namespace std; struct edg { int u,v,next; int w; } edge[5000500]; int head[3000000]; int ans[3000000],vis[3000000]; int num=0; int s,t; struct cmp1 { bool operator ()(const int a,const int b) { return ans[a]>ans[b]; } }; priority_queue <int,vector<int>,cmp1> q; void build(int u,int v,int w) { edge[++num].next=head[u];head[u]=num; edge[num].u=u;edge[num].v=v;edge[num].w=w; } void SPFA(int s) { ans[s]=0; vis[s]=1; q.push(s); while(!q.empty()) { int u=q.top(); q.pop(); vis[u]=0; for(int i=head[u]; i; i=edge[i].next) { int v=edge[i].v; if(ans[v]>edge[i].w+ans[u]) { ans[v]=edge[i].w+ans[u]; if(!vis[v]) { q.push(v); vis[v]=1; } } } } } int main() { int n,m,s; scanf("%d%d%d",&n,&m,&s); for(int i=1; i<=n; i++) ans[i]=INF; for(int i=1; i<=m; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); build(a,b,c); } SPFA(s); for(int i=1; i<=n; i++) printf("%d ",ans[i]); } */ //==========可能負優化的LLL+SLF優化================ /* #include<bits/stdc++.h> #define mokou 2147483647 using namespace std; struct edg { int u,v,w,next; }asd[5000550]; int sum,n,m,s,vis[150000],sp[150000],head[150000]; void put(int a,int b,int c) { asd[++ sum].u = a; asd[sum].v = b; asd[sum].w = c; asd[sum].next = head[a]; head[a] = sum; } deque<int>q; int main(){ int cnt = 1,tot = 0; cin >> n >> m >> s; for(int i = 1;i <= m;i ++) { int u,v,w; cin >> u >> v >> w; put(u,v,w); } for(int i = 1;i <= n;i ++) sp[i] = mokou; sp[s] = 0; vis[s] = 1; q.push_front(s); while(! q.empty()) { int x = q.front(); while(cnt * sp[x] > tot) { q.pop_front(); q.push_back(x); x = q.front(); } q.pop_front(); cnt --, tot -= sp[x], vis[x] = false; for(int i = head[x]; i; i = asd[i].next) if(sp[asd[i].v] > sp[x] + asd[i].w) { sp[asd[i].v] = sp[x] + asd[i].w; if(! vis[asd[i].v]) { vis[asd[i].v] = 1; if(q.empty() || sp[asd[i].v] > sp[q.front()]) q.push_back(asd[i].v); else q.push_front(asd[i].v); cnt++, tot += sp[asd[i].v]; } } } for(int i = 1;i <= n;i ++) cout << sp[i] << " "; } */
有什麼問題能夠在下方評論留言或找我私聊哦
\(QQ:2876140034\)
\(Luogu:Soroak\)spa