Dijkstra
解决无负权图的最短路径问题。
常用模板(Dijkstra+DFS)
1. 记录所有最短路径
#include <bits/stdc++.h>
using namespace std;
const int maxn=2000;//最大顶点数
const int INF=100000;//无穷大
int n;
bool vis[maxn]={false};//vis[i]==true表示顶点i已访问
int d[maxn],G[maxn][maxn];//d记录最短距离
vector<int> pre[maxn];
void Dijkstra(int s)
{
fill(d,d+maxn,INF);
d[s]=0;
for(int i=0;i<n;i++)
{
int u=-1,MIN=INF;
for(int j=0;j<n;j++)
{
if(vis[j]==false&&d[j]<MIN)
{
u=j;
MIN=d[j];
}
}
if(u==-1)return;
vis[u]=true;
for(int v=0;v<n;v++)
{
if(vis[v]==false&&G[u][v]!=INF)
{
if(d[u]+G[u][v]<d[v])
{
d[v]=d[u]+G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if(d[u]+G[u][v]==d[v])
{
pre[v].push_back(u);
}
}
}
}
}
2. 除了最短路径,还有第二个标准评次优
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000; //最大顶点数
const int INF = 100000; //无穷大
int n;
bool vis[maxn] = {false}; //vis[i]==true表示顶点i已访问
int d[maxn], G[maxn][maxn]; //d记录最短距离
vector<int> pre[maxn];
vector<int> path, tempPath; //最优路径,临时路径
int st, optvalue; //st路径起点,第二标准最优值
void Dijkstra(int s)
{
fill(d, d + maxn, INF);
d[s] = 0;
for (int i = 0; i < n; i++)
{
int u = -1, MIN = INF;
for (int j = 0; j < n; j++)
{
if (vis[j] == false && d[j] < MIN)
{
u = j;
MIN = d[j];
}
}
if (u == -1)
return;
vis[u] = true;
for (int v = 0; v < n; v++)
{
if (vis[v] == false && G[u][v] != INF)
{
if (d[u] + G[u][v] < d[v])
{
d[v] = d[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if (d[u] + G[u][v] == d[v])
{
pre[v].push_back(u);
}
}
}
}
}
void DFS(int v)
{
if (v == st)
{
tempPath.push_back(v);
int value;
if (value > optvalue) //大于或小于取决于何为最优
{
optvalue = value;
path = tempPath;
}
tempPath.pop_back();
return;
}
tempPath.push_back(v);
for (int i = 0; i < pre[v].size(); i++)
{
DFS(pre[v][i]);
}
tempPath.pop_back();
}
常见题
边权
新加cost[u][v]表示u->v的花费,增加数组c[maxn],表示从起点到u最少花费为c[u]。初始化c[s]=0,其余c[u]均为INF
for(int v=0;v<n;v++)
{
if(vis[v]==false&&G[u][v]!=INF)
{
if(d[u]+G[u][v]<d[v])
{
d[v]=d[u]+G[u][v];
c[v]=c[u]+cost[u][v];
}
else if(d[u]+G[u][v]==d[v]&&c[u]+cost[u][v]<c[v])
c[v]=c[u]+cost[u][v];
}
点权
用weight[u]表示u点权重,并增加一个数组w[u]表示从起点s到u能收集的最大权值,初始化w[s]为weight[s],其余为0
for(int v=0;v<n;v++)
{
if(vis[v]==false&&G[u][v]!=INF)
{
if(d[u]+G[u][v]<d[v])
{
d[v]=d[u]+G[u][v];
w[v]=w[u]+weight[v];
}
else if(d[u]+G[u][v]==d[v]&&w[u]+weight[v]>w[v])
w[v]=w[u]+weight[v];
}
最短路径条数
只增加一个数组num[ ],表示起点s到u最短路径条数为num[u],初始化num[s]为1,其余为0
for(int v=0;v<n;v++)
{
if(vis[v]==false&&G[u][v]!=INF)
{
if(d[u]+G[u][v]<d[v])
{
d[v]=d[u]+G[u][v];
num[v]=num[u];
}
else if(d[u]+G[u][v]==d[v])
num[v]+=num[u];
}
Floyd
用来解决全源最短问题,给定的图G(V,E),求任意两点u,v之间的最短路径长度。时间复杂度O(n3),由于n3的复杂性决定了顶点数n的限制在200左右。
主要思想
如果存在顶点k,使得以k为中介点时顶点i和顶点j的当前最短距离缩短,则使用顶点k作为顶点i和顶点j的中介点,并更新dis[i][j]的最短距离。
#include<bits/stdc++.h>
using namespace std;
const int INF=10000000;
const int maxn=200;
int n,m;
int dis[maxn][maxn];
void Floyd()
{
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(dis[i][k]!=INF&&dis[k][j]!=INF&&dis[i][k]+dis[k][j]<dis[i][j])
dis[i][j]=dis[i][k]+dis[k][j];
}
int main()
{
int u,v,w;
fill(dis[0],dis[0]+maxn*maxn,INF);
cin>>n>>m;
for(int i=0;i<n;i++)
dis[i][i]=0;
for(int i=0;i<m;i++)
{
cin>>u>>v>>w;
dis[u][v]=w;
}
Floyd();
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
cout<<dis[i][j];
cout<<endl;
}
return 0;
}