不可以存在负环
#include
using namespace std;
const int N = 505;
const int inf = 0x3f3f3f3f;
int d[N][N];
int n, m;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
d[i][j] = (i == j ? 0 : inf);
while (m--) {
int u, v, w;
cin >> u >> v >> w;
d[u][v] = min(d[u][v], w); //有向图
}
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
if (d[1][n] == inf) cout << "-1";
else cout << d[1][n];
}
不能用来求最长路,不可以存在负环
namespace Dijkstra {
const ll inf = (1ll << 60);
int st;//起点
int ed;//终点
struct Edge {
int to;
ll dis;
bool operator<(const Edge &b) const {
return dis > b.dis;
}
};
vector<Edge> e[N];
void add(int u, int v, ll w) {
e[u].push_back({v, w});
e[v].push_back({u, w});
}
priority_queue<Edge> q;
ll d[N];
int inq[N];
void init(int n) {
for (int i = 1; i <= n; i++) {
e[i].clear();
inq[i] = 0;
d[i] = inf;
}
}
// 使用前 请指定 st 和 ed
void dijkstra() {
d[st] = 0;
q.push({st, d[st]});
while (!q.empty()) {
int u = q.top().to;
q.pop();
if (inq[u]) continue;
inq[u] = 1;
for (int i = 0, sz = e[u].size(); i < sz; i++) {
int v = e[u][i].to;
int w = e[u][i].dis;
if (d[v] > d[u] + w) {
d[v] = d[u] + w;
q.push({v, d[v]});
}
}
}
if (d[ed] == inf) {
cout << "No solution" << endl;
} else {
cout << d[ed] << endl;
}
}
}
using namespace Dijkstra;
数组版
// n 50
int dis[N], vis[N];
int pre[N];//记录最短路路径
void dijkstra() {
memset(pre, 0, sizeof pre);
memset(dis, INF, sizeof dis);
memset(vis, 0, sizeof vis);
dis[1] = 0;
pre[1] = 0;
for (int i = 1; i < n; i++) {
int d = INF, f = 0;
//找到当前能够找到的最短路
for (int j = 1; j <= n; j++) {
if (!vis[j] && dis[j] < d) {
d = dis[j], f = j;
}
}
vis[f] = 1;
for (int j = 1; j <= n; j++) {
if (dis[j] > dis[f] + e[f][j]) {
dis[j] = dis[f] + e[f][j];
pre[j] = f;
}
}
}
}
SPFA \texttt{SPFA} SPFA 算法是 Bellman-Ford \texttt{Bellman-Ford} Bellman-Ford 算法的队列优化算法的别称
优点:
1.时间复杂度比普通的 Dijkstra \texttt{Dijkstra} Dijkstra 和 Bellman-Ford \texttt{Bellman-Ford} Bellman-Ford 低
2.能够计算负权图问题
3.能够判断是否有负环 (如果某个点进入队列的次数超过N次则存在负环)
namespace SPFA { //spfa 板子
struct edge {
int to, next;
int w;
} e[N];
int head[N], tot;
void add(int u, int v, int w) {
e[++tot] = {v, head[u], w};
head[u] = tot;
}
/* spfa实现方法:
1.开一个队列 先将开始的节点放入
2.每次从队列中取出一个节点u
遍历与u相通的v节点 查询比对dis[v] 和 dis[u]+w[u,v]
如果dis[v]>dis[u]+w 说明需要更新操作
1.存入最短路
2.由于改变了原有的长度 所以需要往后更新 与这个节点相连的最短路
(即:判断下是否在队列 在就不用重复 不在就加入队列 等待更新)
3.在这期间可以记录这个节点的进队次数,判断是否存在负环
3.直到队空
* */
int dis[N];//最短路
bool vis[N]; //判断是否在队列里
int inq[N]; //入队次数
queue<int> q;
bool spfa(int st) {
memset(vis, false, sizeof(vis));
vis[st] = true;
memset(dis, -1, sizeof(dis));//最长路初始化 -1 最短路初始化INF
dis[st] = 0;
memset(inq, 0, sizeof(inq));
inq[st] = 1;
q.push(st);
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = false;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
int w = e[i].w;
if (dis[v] < dis[u] + w) {
//求最长路 dis[v] < dis[u] + w
//求最短路 dis[v] > dis[u] + w
dis[v] = dis[u] + w;
if (!vis[v]) {
q.push(v);
vis[v] = true;
++inq[v];
if (inq[v] > n + 1) { // inq[v]>点的总数 (包括超级源点)
return false; //有正环(最长路里)或者负环(最短路里)出现 陷入死循环 无解
}
}
}
}
}
return true;
}
}
using namespace SPFA;