学完了单源最短路,总结一下。
,spfa是宽搜
spfa
bool spfa(int s) {
int i, j;
mem(vis, 0);
mem(dis, 0x3f);
mem(times, 0);
queue<int>q;
q.push(s);
dis[s] = 0;
vis[s] = 1;
while (q.size()) {
int i = q.front();
q.pop();
vis[i] = false;
for (j = head[i]; j != -1; j = edge[j].nxt) {
int t = edge[j].t;
if (dis[t] > dis[i] + edge[j].w) {
dis[t] = dis[i] + edge[j].w;
if (vis[t])continue;
vis[t] = 1;
q.push(t);
if (++times[t] > n)
return true;
}
}
}
}
dijkstra
dijkstra是贪心,从一个源点出发,每次选中最近的可达点k,加入以求出最短路的集合,以k为中转点,求出到达其他点的最短路。
算法流程大致如下:
struct edge {
int to, v;
bool operator<(edge b) const {
return v > b.v;
}
} e[maxn << 1];
vector<int> g[maxn];//g[i]存放为邻接i点的边 g[i][j]为第j条边的下标
bool vis[maxn];
void dj_normal(int s) {
mem(d, 0x3f);
mem(vis, 0);
d[s] = 0;
while (1) {
int min_dis = 1e9+1;
int id = -1;
for (int i = 1; i <= n; i++) {
if (vis[i])continue;
if (min_dis > d[i]) {
min_dis = d[i];
id = i;
}
}
if (id == -1)
break;
vis[id]=1;
int len = g[id].size();
for (int j = 0; j < len; j++) {
edge c = e[g[id][j]];
if(vis[c.to])continue;
if (d[c.to] > d[id] + c.v) {
d[c.to] = d[id] + c.v;
}
}
}
}
优化
每次在集合中加入点,都要耗费O(n)的时间来寻找最小值。我们将每次更新后的距离放进堆(优先队列)内,取出的堆顶元素必是最近的点。
需要注意的是:
- 从堆顶取出某点时,堆内可能仍有该点较远距离的数据,舍弃即可
- 若某点已在集合内,其距离不会再更新,不必更新到该点的距离
void dj(int s) {
priority_queue<edge> p;
edge t;
mem(d, 0x3f);
mem(vis, 0);
t.to = s, t.v = 0;
d[s] = 0;
p.push(t);
while (!p.empty()) {
t = p.top();
p.pop();
if (vis[t.to])continue;//堆内可能出现多次该点
vis[t.to] = 1;
int len = g[t.to].size();
for (int j = 0; j < len; j++) {
edge c = e[g[t.to][j]];
if(vis[c.to])continue;
if (d[c.to] > d[t.to] + c.v) {
d[c.to] = d[t.to] + c.v;
if (!vis[c.to]) {
c.v = d[c.to];
p.push(c);
}
}
}
}
}
bellman-ford
bool bf() {
mem(dis, 0x3f);
int i, j;
four(i, 1, n - 1) {//升序for循环
four(j, 0, tot - 1) {
dis[edge[j].t] = Min(dis[edge[j].t], dis[edge[j].f] + edge[j].w);
}
}
return 1;
}
ac代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned un;
# define inf 0x3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define four(a,b,c) for(a=b;a<=c;a++)
#define fourr(a,b,c) for(a=b;a>=c;a--)
#define maxn (int)1e5+3//边
#define maxm (int)1e3+3//点
int Max(int a, int b);
int Min(int a, int b);
struct edge {
int w, t,nxt,f;
}edge[maxn];
struct node {
int id;
int dis;
};
bool operator<(node a, node b) {
return a.dis > b.dis;
}
int head[maxm], tot;
void add_edge(int u, int v, int val) {
edge[tot].t = v;
edge[tot].w = val;
edge[tot].nxt = head[u];
head[u] = tot++;
}
int dis[maxm]; bool vis[maxm]; int n, m, x, times[maxm];
bool bf();
bool spfa(int s);
void dj(int s);
int main() {
mem(head, -1);
tot = 0;
cin >> n >> m >> x;//n个点,m条路,终点x
int i;
four(i, 1, m) {
int u, v, w;
cin >> u >> v >> w;
add_edge(u, v, w);
}
spfa(x);
dj(x);
int ans[maxm], maxx = 0;
mem(ans, 0);
four(i, 1, n)
{
ans[i] += dis[i];//返回的道路
}
four(i, 1, n) {
if (i == x)continue;
//dj(i);
spfa(i);
ans[i] += dis[x];
maxx = Max(maxx, ans[i]);
}
cout << maxx << endl;
}
void dj(int s)
{
priority_queue<node>q;
mem(dis, 0x3f);
mem(vis, 0);
node now;
now.id = s;
now.dis = 0;
dis[s] = 0;
q.push(now);
while (q.size()) {
now = q.top(); q.pop();
int i = now.id, j;
if (vis[i])continue;
vis[i] = 1;
for (j = head[i]; j != -1; j = edge[j].nxt) {
if (dis[edge[j].t] > dis[i] + edge[j].w) {
now.dis = dis[edge[j].t] = dis[i] + edge[j].w;
now.id = edge[j].t;
q.push(now);
}
}
}
}
bool bf() {
mem(dis, 0x3f);
int i, j;
four(i, 1, n - 1) {//升序for循环
four(j, 0, tot - 1) {
dis[edge[j].t] = Min(dis[edge[j].t], dis[edge[j].f] + edge[j].w);
}
}
return 1;
}
bool spfa(int s) {
int i, j;
mem(vis, 0);
mem(dis, 0x3f);
mem(times, 0);
queue<int>q;
q.push(s);
dis[s] = 0;
vis[s] = 1;
while (q.size()) {
int i = q.front();
q.pop();
vis[i] = false;
for (j = head[i]; j != -1; j = edge[j].nxt) {
int t = edge[j].t;
if (dis[t] > dis[i] + edge[j].w) {
dis[t] = dis[i] + edge[j].w;
if (vis[t])continue;
vis[t] = 1;
q.push(t);
if (++times[t] > n)
return true;
}
}
}
}
int Max(int a, int b)
{
return a > b ? a : b;
}
int Min(int a, int b) {
return a < b ? a : b;
}