【图论】最短路
SPFA
SPFA : Shortest Path Faster Algorithm
SPFA 概述
SPFA的入队规则:该点的dis变小后,需要入队。
vis[x]
x是否在队列中
把dis初始化为无穷大; vis[i] 全部清零
dis[起点]=0;
起点入队;
- 取出队首x;
vis[x] = 0
- 枚举x的所有邻居y;
注意:和BFS不同
if(dis[y] > dis[x] + /*边长*/)
{
dis[y] = dis[x] + /*边长*/;
if(vis[y] == 0)
q.push(y);
}
SPFA 代码示例
单源最短路(弱化)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
using namespace std;
//快乐头文件
vector<int> g[10010]; //图邻接表
vector<int> w[10010]; //边权
int dis[10010]; //最短路径长度
bool vis[10010]; //是否在队中
queue<int> q; //spfa队列
void spfa(int start)
{
memset(dis, 999999, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[start] = 0;
q.push(start);
while(!q.empty())
{
int x = q.front();
q.pop();
vis[x] = 0;
for(int i = 0;i < g[x].size();i++)
{
if(dis[g[x][i]] > dis[x] + w[x][i])
{
dis[g[x][i]] = dis[x] + w[x][i];
if(vis[g[x][i]] == 0)
q.push(g[x][i]);
}
}
}
}
int main()
{
int n, m, s;
cin >> n >> m >> s;
for(int i = 1;i <= m;i++)
{
int u, v, ww;
scanf("%d%d%d", &u, &v, &ww);
g[u].push_back(v);
w[u].push_back(ww);
}
spfa(s);
for(int i = 1;i <= n;i++)
{
cout << dis[i] << " ";
}
return 0;
}
SPFA 判断负环
某个点入队次数过多,则存在负环
什么是过多?
入队次数 \(≥n\) 次,说明有负环。
vector<int> g[2010]; //图邻接表
vector<int> w[2010]; //边权
int dis[2010]; //最短路径长度
bool vis[2010]; //是否在队中
int cnt[2010];
int n,m;
void spfa(int start)
{
queue<int> q; //spfa队列
memset(dis, 999999, sizeof(dis));
memset(vis, 0, sizeof(vis));
memset(cnt, 0, sizeof(cnt));
dis[start] = 0;
q.push(start);
while(!q.empty())
{
int x = q.front();
q.pop();
vis[x] = 0;
for(int i = 0;i < g[x].size();i++)
{
if(dis[g[x][i]] > dis[x] + w[x][i])
{
dis[g[x][i]] = dis[x] + w[x][i];
if(vis[g[x][i]] == 0)
{
q.push(g[x][i]);
if(++cnt[g[x][i]] >= n)
{
puts("YES");
return;
}
vis[g[x][i]] = 1;
}
}
}
}
puts("NO");
return;
}
Dijkstra
Dijkstra : 迪杰斯特拉算法
Dijkstra 概述
把dis初始化为无穷大;
dis[起点]=0;
for(int i to n)
{
从集合(vis[u] == 0)中选出dis最小的点u;
把u从集合移出; vis[u] = 1;
访问u的所有邻居v;
if(dis[v] > dis[u] + u到v边长)
dis[v] = dis[u] + u到v边长;
}
Dijkstra 代码示例
基本写法 \(O(n^2)\)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
vector<int> g[2510];
vector<int> w[2510];
bool vis[2510];
int dis[2510];
int main()
{
int n, m, ts, te;
cin >> n >> m >> ts >> te;
for(int i = 1;i <= m;i++)
{
int u, v, l;
scanf("%d%d%d", &u, &v, &l);
g[u].push_back(v);
g[v].push_back(u);
w[u].push_back(l);
w[v].push_back(l);
}
memset(dis, 999999, sizeof(dis));
dis[ts] = 0;
for(int i = 1;i <= n;i++)
{
int pos = 0;
for(int j = 1;j <= n;j++)
{
if(vis[j]) continue;
if(dis[j] < dis[pos]) pos = j;
}
vis[pos] = 1;
for(int j = 0;j < g[pos].size();j++)
{
int v = g[pos][j];
if(dis[v] > dis[pos] + w[pos][j])
dis[v] = dis[pos] + w[pos][j];
}
}
cout << dis[te];
return 0;
}
堆优化 \(O(m\log m)\)
稠密图:\(O(n^2\log n)\)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
struct Node
{
int id, key;
bool operator < (const Node &y) const
{
return key > y.key;
}
};
vector<int> g[100010];
vector<int> w[100010];
priority_queue<Node> q;
bool vis[100010];
int dis[100010];
int main()
{
int n, m, ts;
cin >> n >> m >> ts;
for(int i = 1;i <= m;i++)
{
int u, v, l;
scanf("%d%d%d", &u, &v, &l);
g[u].push_back(v);
w[u].push_back(l);
}
memset(dis, 0x3f, sizeof(dis));
dis[ts] = 0;
q.push({ts, 0});
while(!q.empty())
{
int u = q.top().id;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int j = 0;j < g[u].size();j++)
{
int v = g[u][j];
if(dis[v] > dis[u] + w[u][j])
{
dis[v] = dis[u] + w[u][j];
q.push({v, dis[v]});
}
}
}
for(int i = 1;i <= n;i++)
cout << dis[i] << " ";
return 0;
}
Dijkstra的DP
方案数
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
struct Node
{
int id, key;
bool operator < (const Node &y) const
{
return key > y.key;
}
};
vector<int> g[1000010];
priority_queue<Node> q;
bool vis[10000100];
int dis[1000010];
long long f[1000010];
int main()
{
int n, m;
cin >> n >> m;
for(int i = 1;i <= m;i++)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
memset(dis, 999999, sizeof(dis));
dis[1] = 0;
f[1] = 1;
q.push({1, 0});
while(!q.empty())
{
int u = q.top().id;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int j = 0;j < g[u].size();j++)
{
int v = g[u][j];
if(dis[v] > dis[u] + 1) // 水沝淼㵘题
{
f[v] = f[u];
dis[v] = dis[u] + 1;
q.push({v, dis[v]});
}
else if(dis[v] == dis[u] + 1) // 水沝淼㵘题
{
f[v] += f[u];
f[v] %= 100003;
}
}
}
for(int i = 1;i <= n;i++)
cout << f[i] << "\n";
return 0;
}
Floyd
for(int k = 1;k <= n;k++)
{
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)
{
if(f[i][j] > f[i][k] + f[k][j])
{
f[i][j] = f[i][k] + f[k][j];
}
}
}
}
本文来自博客园,作者:GHIvan,转载请注明原文链接:https://www.cnblogs.com/ghivan911/p/17475942.html,洛谷个人主页:https://www.luogu.com.cn/user/531036