注意!!!下面的模板有的並沒有去設定具體的無法到達的極限值,也沒有考慮極限相加爆表的情況,如果可以的話,最好還是把dis數組定義成long long
Floyd算法(僅僅四行的算法)
Floyd算法僅僅四行就能解決問題但是時間復雜度達到了感人的O(n^3),唯一的有點是能夠輸出任意兩點之間的最小路徑,這或許是他唯一的用途了吧。
偽代碼
初始化
賦值如果i==j為0其余為inf
建圖
Floyd四行代碼
輸出
代碼模板
#include <bits/stdc++.h>
using namespace std;
int G[10005][10005];
int main()
{
//n為節點數,m為邊的條數
int n,m;
cin>>n>>m;
//初始化,如果i==j那么G[i][j]就是0
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
G[i][j]=i==j?0:999999999;
//建圖
while(m--)
{
int t1,t2,t3;
cin>>t1>>t2>>t3;
G[t1][t2]=t3;
}
//Floyd算法的核心,4行代碼解決
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
//輸出答案
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<<G[i][j]<<" ";
cout<<endl;
}
return 0;
}
Floyd可以解決任意兩個節點之間的最短路,而且在稀疏圖有着還可以的時間復雜度
Dijkstra算法
無優化原始版本
時間復雜度的進一步的降低,能夠算出源節點到各個節點之間的最短路
偽代碼
初始化
賦值如果i==j為0其余為inf
建圖
初始化dis數組與bk數組
bk[s]=1;
循環n次
尋找離要找節點最近的節點
bk[u]=1;
嘗試每個節點是否能夠被這個最近的節點松弛
循環結束
輸出dis數組
代碼模板
#include <bits/stdc++.h>
using namespace std;
int G[10010][10010];
int dis[10010];
int bk[10010];
int main()
{
int n,m,s;
cin>>n>>m>>s;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
G[i][j]=i==j?0:999999999;
while(m--)
{
int t1,t2,t3;
cin>>t1>>t2>>t3;
G[t1][t2]=t3;
}
for(int i=1;i<=n;i++)
dis[i]=G[s][i];
memset(bk,0,sizeof(bk));
bk[s]=1;
for(int i=1;i<=n;i++)
{
int x,minn=999999999;
for(int j=1;j<=n;j++)
if(dis[j]<minn&&!bk[j])
minn=dis[x=j];
bk[x]=1;
for(int j=1;j<=n;j++)
dis[j]=min(dis[j],dis[x]+G[x][j]);
}
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
return 0;
}
復雜度O(n^2)
vector建圖優化
因為我們用鄰接矩陣建圖很有可能會爆內存,所以可以采用vector數組建圖優化。遇到較大的數據可以采用。
vector優化模板
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node
{
int to,cost;
};
vector<node> G[500005];
int bk[500005];
ll dis[500005];
const int inf=INT_MAX;
int main()
{
//freopen("data.in","r",stdin);
int m,n,s;
cin>>n>>m>>s;
while(m--)
{
int t1,t2,t3;
cin>>t1>>t2>>t3;
node e;
e={t2,t3};
G[t1].push_back(e);
}
for(int i=1;i<=n;i++)
dis[i]=i==s?0:inf;
for(int i=1;i<=n;i++)
{
int x,y=inf;
for(int j=1;j<=n;j++)
if(!bk[j]&&dis[j]<=y)
y=dis[x=j];
bk[x]=1;
for(int j=0;j<G[x].size();j++)
dis[G[x][j].to]=min(dis[G[x][j].to],dis[x]+G[x][j].cost);
}
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
}
實際上根據題目的要求如果無法到達的話要進行各種的輸出,最好定義dis數組為ll為妙
最終優化vector+優先隊列
直接硬性把時間設置成MlogN
模板代碼
#include <bits/stdc++.h>
using namespace std;
struct node //存入優先隊列中的結構體
{
int num;
int cost;
bool operator < (const node&a) const
{
return cost>a.cost;
}
};
struct edge//存入vector中的
{
int to,cost;
};
int dis[10005];
int bk[10005];
const int inf=INT_MAX;
vector <edge> G[10005];
priority_queue <node> q;
int main()
{
int n,m,s;
cin>>n>>m>>s;
while(m--) //建圖
{
int t1,t2,t3;
cin>>t1>>t2>>t3;
edge e={t2,t3};
G[t1].push_back(e);
}
for(int i=1;i<=n;i++)//初始化dis數組
dis[i]=i==s?0:inf;
bk[s]=1;
q.push((node){s,0});
while(!q.empty())
{
node a=q.top();
q.pop();
if(dis[a.num]!=a.cost)//判斷條件剪枝
continue;
bk[a.num]=1;
for(int i=0;i<G[a.num].size();i++)
if(!bk[G[a.num][i].to])
{
if(dis[G[a.num][i].to]>dis[a.num]+G[a.num][i].cost)
{
dis[G[a.num][i].to]=dis[a.num]+G[a.num][i].cost;
q.push((node){G[a.num][i].to,dis[G[a.num][i].to]});
}
}
}
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
}
Bellman-Ford算法(真的三行。。。。)
基本的思路與dijkstra差不多,但是能夠解決負權圖
偽代碼
初始化
初始化dis數組
Bellman-Ford算法
輸出dis數組
無優化版本
#include <bits/stdc++.h>
using namespace std;
int num[500005],to[500005],cost[500005];
long long dis[100005];
const int inf=INT_MAX;
int main()
{
int n,m,s;
cin>>n>>m>>s;
for(int i=1;i<=m;i++)
cin>>num[i]>>to[i]>>cost[i];
for(int i=1;i<=n;i++)
dis[i]=i==s?0:inf;
for(int k=1;k<=n-1;k++)
for(int i=1;i<=m;i++)
dis[to[i]]=min(dis[to[i]],dis[num[i]]+cost[i]);
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
}
SPFA
近似於無敵的算法,但是對於解決非負權邊的單源最短路還是用dij+優先隊列優化得了
沙雕圖

廢話少說直接上模板
#include <bits/stdc++.h>
using namespace std;
struct edge
{
int to,cost;
};
int dis[100005];
int bk[100005];
vector<edge> G[100005];
queue<int> q;
const int inf=INT_MAX;
int main()
{
int n,m,s;
cin>>n>>m>>s;
while(m--)
{
int t1,t2,t3;
cin>>t1>>t2>>t3;
G[t1].push_back((edge){t2,t3});
}
for(int i=1;i<=n;i++)
dis[i]=i==s?0:inf;
q.push(s);
while(!q.empty())
{
int p=q.front();
q.pop();
bk[p]=0;
for(int i=0;i<G[p].size();i++)
{
if(dis[G[p][i].to]>dis[p]+G[p][i].cost)
{
dis[G[p][i].to]=dis[p]+G[p][i].cost;
if(!bk[G[p][i].to])
{
q.push(G[p][i].to);
bk[G[p][i].to]=1;
}
}
}
}
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
}
總結
如果每個節點之間的最小路徑需要求出的話,那么還是用Floyd吧,對於非負圖看n和m如果m都比n大了,那么最好還是老老實實的用Dijkstra+優先隊列吧,如果出現負權圖,那么還是老老實實SPFA