SPFA
title: SPFA
categories:
- ICPC
tags: - null
abbrlink: 33b8c865
date: 2024-09-04 00:00:00
SPFA
最短路:保证数据不存在负环的情况下,求1-n最短路
struct edge {
int v, w;
};
void solve() {
int n, m;
cin >> n >> m;
vector<vector<edge>> e(n + 1);
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({v, w});
}
vector<int> dis(n + 1, inf);
auto spfa = [&]() {
vector<bool> st(n + 1);
queue<int> q;
q.push(1);
st[1] = true;
dis[1] = 0;
while (q.size()) {
auto u = q.front();
q.pop();
st[u] = 0;
for (auto [v, w] : e[u]) {
if (dis[u] + w < dis[v]) {
dis[v] = dis[u] + w;
if (st[v] == 0) {
q.push(v);
st[v] = true;
}
}
}
}
if (dis[n] == inf)
return false;
return true;
};
for (int i = 1; i <= n; i++) deb(i, dis[i]);
if (spfa())
cout << dis[n] << endl;
else
cout << "impossible" << endl;
}
判断全局图中是不是存在负环
struct edge {
int v, w;
};
void solve() {
int n, m;
cin >> n >> m;
vector<vector<edge>> e(n + 1);
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({v, w});
}
vector<int> dis(n + 1, inf);
vector<int> cnt(n + 1);
auto judgefu = [&]() {
vector<bool> st(n + 1, 1);
queue<int> q;
for (int i = 1; i <= n; i++) q.push(i);
while (q.size()) {
auto u = q.front();
q.pop();
st[u] = 0;
for (auto [v, w] : e[u]) {
if (dis[u] + w < dis[v]) {
dis[v] = dis[u] + w;
cnt[v] = cnt[u] + 1;
if (cnt[v] >= n)
return true;
if (st[v] == 0) {
q.push(v);
st[v] = true;
}
}
}
}
return false;
};
if (judgefu())
cout << "Yes" << endl;
else
cout << "No" << endl;
}
从顶点 1出发能到达的负环
struct edge {
int v, w;
};
void solve() {
int n, m;
cin >> n >> m;
vector<vector<edge>> e(n + 1);
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({v, w});
if (w >= 0)
e[v].push_back({u, w});
}
vector<int> dis(n + 1, inf);
vector<int> cnt(n + 1);
auto judgefu = [&]() {
vector<bool> st(n + 1, 0);
queue<int> q;
q.push(1);
st[1] = 1;
dis[1] = 0;
while (q.size()) {
auto u = q.front();
q.pop();
st[u] = 0;
for (auto [v, w] : e[u]) {
if (dis[u] + w < dis[v]) {
dis[v] = dis[u] + w;
cnt[v] = cnt[u] + 1;
if (cnt[v] >= n)
return true;
if (st[v] == 0) {
q.push(v);
st[v] = true;
}
}
}
}
return false;
};
if (judgefu())
cout << "YES" << endl;
else
cout << "NO" << endl;
}
- 差分约束
给出一组包含 个不等式,有 个未知数的形如:
的不等式组,求任意一组满足这个不等式组的解。
第一行为两个正整数 ,代表未知数的数量和不等式的数量。
接下来 行,每行包含三个整数 ,代表一个不等式 。
一行, 个数,表示 的一组可行解,如果有多组解,请输出任意一组,无解请输出 NO
。
一、 求不等式组的可行解
!!!源点需要满足的条件:从源点
出发,一定可以走到所有的边。!!!
步骤:
1. 先将每个不等式 ,转化成一条从 走到 ,长度为 的边。
2. 找到一个超级源点
,使得该源点一定可以遍历到所有边
3. 从源点求一遍单源最短路
结果1:如果存在负环
,则原不等式组一定无解
结果2:如果没有负环
,则 就是原不等式组的一个可行解
二、 如何求最大值或者最小值,这里的最值指的是每个变量的最值(独立但可以同时取到)
结论:如果求的是最小值
,则应该求最长路
;如果求的是最大值
,则应该求最短路
。
问题:如何转化 ,其中 是一个常数,这类的不等式。
方法:建立一个超级源点0
,然后建立 0 -> i
的边,长度是 即可。
以求 的最大值
为例:
求所有从 出发,构成的多个形如如下的不等式链
所计算出的上界
,最终 的最大值等于所有上界的最小值
。
这里所有上界的最小值
可以理解这么一个例子:
把上述转换成图论
的问题,就是求 的最小值
,即最短路
求解
- 求 的
最小值
时则完全相反,求一个形如如下不等式链
所计算出的下界
,最终在所有下界里取最大值
转换成图论
的问题,就是求 的最大值
,即最长路
求解
建边技巧:
-
如何转化 ,其中 是一个常数,这类的不等式。
方法:建立一个超级源点
0
,然后建立0 -> i
的边,长度是 即可。 -
-
-
x_a=x_b \to addedge(a,b,0) \and addedge(b,a,0)
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 爱飞鱼的blog!