[例题]
洛谷P4779 【模板】单源最短路径(标准版)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair pii;
const int M = 2e5 + 10;
const ll INF = 0x3f3f3f3f;
int n, m, s, cnt = 0;
struct edges {
int w, to, next;
edges(int a = 0, int b = 0, int c = -1) : w(b), to(a), next(c) {}
};
vector head, dis;
vector edge;
inline void add(int u, int v, int w) {
edge[++cnt] = edges(v, w, head[u]);
head[u] = cnt;
}
void dij() {
vector vis(n + 1, false);
dis = vector(n + 1, INF);
priority_queue, greater > heap;
dis[s] = 0;
heap.push(make_pair(0, s));
while (heap.size()) {
int u = heap.top().second;
heap.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
heap.push(make_pair(dis[v], v));
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
scanf("%d%d%d", &n, &m, &s);
head = vector(n + 1, -1);
edge = vector(m + 1);
for (int i = 0; i < m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
dij();
for (int i = 1; i <= n; i++) {
printf("%d ", dis[i]);
}
puts("");
return 0;
}
洛谷P1629 邮递员送信
#include
#include
#include
#include
#define mk(a, b) make_pair(a, b)
using namespace std;
typedef pair pii;
const int INF = 0x3f3f3f3f;
int n, m, cnt = 0;
vector dis, ddis, head, head2;
struct edges {
int to, w, next;
edges(int a = 0, int b = 0, int c = -1) : to(a), w(b), next(c) {}
};
vector edge, bk;
void init() {
head = vector(n + 1, -1);
head2 = vector(n + 1, -1);
dis = vector(n + 1, INF);
ddis = vector(n + 1, INF);
edge = vector(m + 1);
bk = vector(m + 1);
}
void add(int u, int v, int w) {
edge[++cnt] = edges(v, w, head[u]);
bk[cnt] = edges(u, w, head2[v]);
head[u] = cnt;
head2[v] = cnt;
}
void dij() {
priority_queue heap;
vector vis(n + 1, false);
heap.push(mk(0, 1));
while (heap.size()) {
int u = heap.top().second;
heap.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
heap.push(mk(-dis[v], v));
}
}
}
}
void dij2() {
priority_queue heap;
vector vis(n + 1, false);
heap.push(mk(0, 1));
while (heap.size()) {
int u = heap.top().second;
heap.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = head2[u]; ~i; i = bk[i].next) {
int v = bk[i].to, w = bk[i].w;
if (ddis[v] > ddis[u] + w) {
ddis[v] = ddis[u] + w;
heap.push(mk(-ddis[v], v));
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
scanf("%d%d", &n, &m);
init();
for (int i = 0; i < m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
dis[1] = ddis[1] = 0;
dij();
dij2();
int ans = 0;
for (int i = 1; i <= n; i++) {
ans += dis[i] + ddis[i];
}
printf("%d", ans);
return 0;
}
洛谷P1144 最短路计数
#include
using namespace std;
typedef pair pii;
const int M = 1e6 + 5;
int n, m, dis[M], head[M], ans[M], cnt = 0;
struct es {
int to, next;
es(int a = 0, int b = -1) : to(a), next(b) {}
} e[M << 2];
void add(int a, int b) {
e[++cnt] = es(b, head[a]);
head[a] = cnt;
}
void dij() {
for (int i = 2; i <= n; i++) {
dis[i] = 0x3f3f3f3f;
}
ans[1] = 1;
vector vis(n + 1, false);
priority_queue heap;
heap.push(make_pair(0, 1));
while (heap.size()) {
int u = heap.top().second;
heap.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (dis[v] > dis[u] + 1) {//松弛操作
dis[v] = dis[u] + 1;
ans[v] = ans[u];
heap.push(make_pair(-dis[v], v));
} else if (dis[u] + 1 == dis[v]) {
ans[v] += ans[u];
ans[v] %= 100003;
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
scanf("%d%d", &n, &m);
memset(head, -1, sizeof head);
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
dij();
for (int i = 1; i <= n; i++) {
if (ans[i] >= 100003) ans[i] = 0;
printf("%d\n", ans[i]);
}
return 0;
}
这个算法更多的不是用来计算最短路,而是用来计算是否有负环或者正环(负环dis初始化为INF,正环dis初始化为0)
【例题】
EOlymp - 1453 Ford-Bellman
#include
#include
#include
#include
using namespace std;
const int INF = 0x3f3f3f3f;
int n, m;
vector dis;
struct edges {
int u, v, w;
edges(int u = 0, int v = 0, int w = 0) : u(u), v(v), w(w) {}
};
vector e;
int add(int a, int b) { //无穷大加任何数还是无穷大
if (a == INF || b == INF) return a;
return a + b;
}
void bf() {
bool flag;
while (true) {
flag = true;
for (int j = 0; j < m; j++) {
if (dis[e[j].v] > add(dis[e[j].u], e[j].w)) {
dis[e[j].v] = dis[e[j].u] + e[j].w;
flag = false;
}
}
if (flag) return;
}
}
int main() {
scanf("%d%d", &n, &m);
dis = vector(n + 1, INF);
for (int i = 0; i < m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
e.push_back(edges(u, v, w));
}
dis[1] = 0;
bf();
for (int i = 1; i <= n; i++) {
if (dis[i] == INF) dis[i] = 30000;
printf("%d ", dis[i]);
}
puts("");
return 0;
}
POJ 2240 Arbitrage
#include
#include
#include
POJ 3259 Wormholes
代码如下
#include
#include
#include
#include
using namespace std;
const int M = 3e3;
int n, m, ww, f, dis[510];
struct es {
int u, v, w;
es(int a = 0, int b = 0, int c = 0) : u(a), v(b), w(c) {}
};
vector e;
bool bf() {
for (int i = 1; i <= n; i++) {
bool flag = true;
for (int j = 0; j < m + m + ww; j++) {
if (dis[e[j].v] > dis[e[j].u] + e[j].w) {
dis[e[j].v] = dis[e[j].u] + e[j].w;
flag = false;
}
}
if (flag) break;
if (i == n) return true;//有负环,因为松弛了 n 次
}
return false;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
scanf("%d", &f);
while (f--) {
scanf("%d%d%d", &n, &m, &ww);
int u, v, w;
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &u, &v, &w);
e.push_back(es(u, v, w));
e.push_back(es(v, u, w));
}
for (int i = 0; i < ww; i++) {
scanf("%d%d%d", &u, &v, &w);
e.push_back(es(u, v, -w));
}
memset(dis, 0x3f, sizeof dis);
dis[1] = 0;
if (bf()) puts("YES");
else puts("NO");
e.clear();
}
return 0;
}
POJ 1860 Currency Exchange
代码如下
#include
#include
#include
using namespace std;
const int M = 300;
int n, m, s;
double vv, dis[M] = {0}; //vv是一开始手中的钱的数量
struct es {
int u, v;
double r, c;
es(int a = 0, int b = 0, double c = 0, double d = 0) : u(a), v(b), r(c), c(d) {}
} e[M];
bool bf() {
for (int i = 1; i <= n - 1; i++) {
for (int j = 0; j < m + m; j++) {
if (dis[e[j].v] < (dis[e[j].u] - e[j].c) * e[j].r) {
dis[e[j].v] = (dis[e[j].u] - e[j].c) * e[j].r;
}
}
}
for (int j = 0; j < m + m; j++) {
if (dis[e[j].v] < (dis[e[j].u] - e[j].c) * e[j].r) {
return true; //手中的钱变多了
}
}
return false;//手中的钱没变或者少了
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
scanf("%d%d%d%lf", &n, &m, &s, &vv);
for (int i = 0; i < m; i++) {
int u, v;
double a, b, c, d;
scanf("%d%d%lf%lf%lf%lf", &u, &v, &a, &b, &c, &d);
e[i << 1] = es(u, v, a, b); //一个兑换点有从 a -> b,
e[i << 1 | 1] = es(v, u, c, d); //也有从 b -> a
}
dis[s] = vv;
if (bf()) puts("YES");
else puts("NO");
return 0;
}
POJ 2253 Frogger
#include
#include
#include
#include
#include
using namespace std;
const int M = 2e2 + 10;
int n, x[M], y[M], test = 0;
double dis[M][M];
void Floyd() {
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (dis[i][j] > max(dis[i][k], dis[k][j])) {
dis[i][j] = max(dis[i][k], dis[k][j]);
}
// dis[i][j] = min(dis[i][j], max(dis[i][k], dis[k][j]));//更清晰的代码
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
while (scanf("%d", &n), n) {
scanf("%d%d%d%d", &x[1], &y[1], &x[2], &y[2]);
double a = x[2] - x[1], b = y[2] - y[1];
dis[1][2] = sqrt(a * a + b * b);
for (int i = 3; i <= n; i++) {
scanf("%d%d", &x[i], &y[i]);
for (int j = 1; j < i; j++) {
a = x[i] - x[j], b = y[i] - y[j];
dis[i][j] = sqrt(a * a + b * b);
dis[j][i] = dis[i][j];
}
}
Floyd();
printf("Scenario #%d\nFrog Distance = %.3f\n\n", ++test, dis[1][2]);
memset(dis, 0, sizeof dis);
}
return 0;
}
POJ 1125 Stockbroker Grapevine
#include
#include
#include
#include
#include
using namespace std;
const int M = 110;
int n, tm[M][M], dis[M][M];
void floyd() {
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
while (scanf("%d", &n), n) {
memset(dis, 0x3f, sizeof dis);
memset(tm, 0x3f, sizeof tm);
for (int i = 1; i <= n; i++) {
int m;
scanf("%d", &m);
for (int j = 0; j < m; j++) {
int x, y;
scanf("%d%d", &x, &y);
dis[i][x] = y;
}
}
floyd();
int ans = -1, Min = 0x3f3f3f3f;
for (int i = 1; i <= n; i++) {
int Max = 0;
for (int j = 1; j <= n; j++) {
if (i != j && dis[i][j] > Max) {
Max = dis[i][j];
}
}
if (Max < Min) {
ans = i;
Min = Max;
}
}
if (Min == 0x3f3f3f3f) {
puts("disjoint");
continue;
}
printf("%d %d\n", ans, Min);
}
return 0;
}
一种速度极快的最短路算法,但是听说被一位大佬卡死了,但是在一些题目上还是能用的,下面利用这个算法来解决上面的一些题
存图的方式最好是邻接表法,这样比较方便松弛
其实道理都差不多,题目的不同,主要修改的就是松弛操作部分的代码
【例题】
POJ 3259 Wormholes
#include
#include
#include
#include
#include
using namespace std;
const int M = 2e4;
int n, m, ww, f, dis[510], head[510], cnt = 0;
struct es {
int to, w, next;
es(int a = 0, int b = 0, int c = -1) : to(a), w(b), next(c) {}
};
vector e;
void add(int u, int v, int w) {
e[++cnt] = es(v, w, head[u]);
head[u] = cnt;
}
bool spfa() {
queue q;
vector inq(n + 1);
vector nums(n + 1, 0);
q.push(1);
inq[1] = true;
nums[1]++;
while (q.size()) {
int u = q.front();
q.pop();
inq[u] = false;
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to, w = e[i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!inq[v]) {
q.push(v);
inq[v] = true;
nums[v]++;
if (nums[v] >= n)
return true;
}
}
}
}
return false;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
scanf("%d", &f);
while (f--) {
cnt = 0;
memset(head, -1, sizeof head);
scanf("%d%d%d", &n, &m, &ww);
e = vector(m + m + ww + 1);
int u, v, w;
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
for (int i = 0; i < ww; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, -w);
}
memset(dis, 0x3f, sizeof dis);
dis[1] = 0;
if (spfa()) puts("YES");
else puts("NO");
e.clear();
}
return 0;
}
原地址