最短路问题分为单源和多源,源就是起点的意思,所以多源是多起点问题;
单源问题,要讨论边权
边权为正
使用Dijkstra算法
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510;
int g[N][N];
int dist[N];
bool st[N];
int n,m;
int dijkstra()
{
memset(dist,0x3f,sizeof dist);
dist[1]=0;
for(int j=0;j<n;j++)
{
int t=-1;
for(int i=1;i<=n;i++)
if(!st[i]&&(t==-1||dist[t]>dist[i])) t=i;
for(int i=1;i<=n;i++)
dist[i]=min(dist[i],dist[t]+g[t][i]);
st[t]=true;
}
if(dist[n]==0x3f3f3f3f) return -1;
return dist[n];
}
int main()
{
cin>>n>>m;
memset(g,0x3f,sizeof g);
while (m -- )
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
}
cout<<dijkstra()<<endl;
return 0;
}
时间复杂度度为n^2 还有一个堆优化版本
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6+10;
int h[N], e[N], w[N], ne[N], idx;
int dist[N];
bool st[N];
int n,m;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra() // 求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 1});
while (heap.size())
{
auto t=heap.top();
heap.pop();
int ver=t.second,distance=t.first;
if(st[ver]) continue;
st[ver]=true;
for(int i = h[ver];i != -1; i = ne[i])
{
int j = e[i];
if(dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
heap.push({dist[j],j});
}
}
}
if (dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main()
{
memset(h, -1, sizeof h);
cin>>n>>m;
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
cout<<dijkstra()<<endl;
return 0;
}
时间复杂度是mlogn;
边权为负
bellman-ford算法 这个算法时间复杂度是n*m;
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6+10;
struct app{
int a,b,c;
}a[N];
int dist[N],distup[N];
int n,m,k;
void bellman_ford()
{
memset(dist,0x3f,sizeof dist);
dist[1]=0;
for(int i=0;i<k;i++)
{
memcpy(distup,dist,sizeof dist);
for(int i=0;i<m;i++)
{
dist[a[i].b]=min(dist[a[i].b],distup[a[i].a]+a[i].c);
}
}
}
int main()
{
cin>>n>>m>>k;
for(int i=0;i<m;i++) cin>>a[i].a>>a[i].b>>a[i].c;
bellman_ford();
if(dist[n]>0x3f3f3f3f/2) puts("impossible");
else cout<<dist[n];
}
优化版本是spfa算法
spfa算法的时间复杂度一般为m,最坏为n*m;
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e6+10;
int h[N], e[N], w[N], ne[N], idx;
int dist[N];
bool st[N];
int n,m;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int spfa()
{
queue<int>q;
memset(dist,0x3f,sizeof dist);
q.push(1);
dist[1]=0;
st[1]=true;
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
if(!st[j])
{
st[j]=true;
q.push(j);
}
}
}
}
return dist[n];
}
int main()
{
cin>>n>>m;
memset(h, -1, sizeof h);
while (m -- )
{
int a,b,c;
cin>>a>>b>>c;
add(a, b, c);
}
int t=spfa();
if(t==0x3f3f3f3f) puts("impossible");
else cout<<t;
}
spfa还可以求负环 代码如下
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e6+10;
int h[N],ne[N],e[N],idx,w[N];
int dist[N],cnt[N];
bool st[N];
int n,m;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa()
{
queue<int> q;
for(int i=1;i<=n;i++)
{
q.push(i);
st[i]=true;
}
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n) return true;
if(!st[j])
{
st[j]=true;
q.push(j);
}
}
}
}
return false;
}
int main()
{
memset(h, -1,sizeof h);
cin>>n>>m;
while (m -- )
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
if(spfa()) puts("Yes");
else puts("No");
}
但是有边数限制的只能使用bellman-ford算法
小总结
dijstra堆优化算法和spfa算法是图宽搜,可以简单记忆中间部分
图宽搜的代码如下
queue<int> q;
st[1] = true; // 表示1号点已经被遍历过
q.push(1);
while (q.size())
{
int t = q.front();
q.pop();
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (!st[j])
{
st[j] = true; // 表示点j已经被遍历过
q.push(j);
}
}
}
多源问题
使用Floyd算法
这个算法原理是根据区间动态规划.
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5110,INT=1e9;
int g[N][N];
int n,m,q;
void floyd()
{
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]);
}
int main()
{
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) g[i][j]=0;
else g[i][j]=INT;
while (m -- )
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
}
floyd();
while (q -- )
{
int a,b;
cin>>a>>b;
if(g[a][b]>=INT/2) puts("impossible");
else cout<<g[a][b]<<endl;
}
}
=============================================
以上就是图论里面最短路部分,如有错误希望大佬能够指点一二