Skip to content

Commit 1d651df

Browse files
committed
[AcWing Base, Graph Dijkstra]
1 parent 62a0db8 commit 1d651df

File tree

8 files changed

+470
-0
lines changed

8 files changed

+470
-0
lines changed

Graph/ShortestPath/AW849Dijkstra1.cpp

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
Dijkstra
3+
https://www.acwing.com/problem/content/description/851/
4+
1. find next point (p) closest to source.
5+
2. the shortest path length from source to p is determined.
6+
3. update all other points, as p is determined: min(dist[k], dist[p] + g[p][k])
7+
8+
n <= 500
9+
m <= 10^5
10+
朴素版: for 稠密图
11+
O(n^2) = 2.5e5
12+
13+
输入样例:
14+
3 3
15+
1 2 2
16+
2 3 1
17+
1 3 4
18+
输出样例:
19+
3
20+
*/
21+
22+
#include <bits/stdc++.h>
23+
using namespace std;
24+
25+
const int N = 510;
26+
const int INFBYTE = 0x3f;
27+
const int INFINT = 0x3f3f3f3f;
28+
int n, m;
29+
int g[N][N]; /* g[i][j]: distance between i and j */
30+
int dist[N]; /* dist[i]: 1 to i shortest path distance */
31+
bool st[N]; /* true if dist[i] is determined */
32+
33+
int dijistra() {
34+
memset(dist, 0x3f, sizeof(dist));
35+
dist[1] = 0;
36+
for(int i = 0; i < n - 1; i++) { /* n */
37+
int t = -1;
38+
for(int j = 1; j <= n; j++) {
39+
/* find closeset point that not determined */
40+
if(!st[j] and (t == -1 or dist[t] > dist[j])) {
41+
t = j;
42+
}
43+
}
44+
st[t] = true;
45+
/* 1 -> t determined, find next point j,
46+
** min 1->t->j = dist[t] + min(g[t][j]) */
47+
for(int j = 1; j <= n; j++) {
48+
dist[j] = min(dist[j], dist[t] + g[t][j]);
49+
}
50+
}
51+
if(dist[n] == INFINT) {
52+
return -1;
53+
} else {
54+
return dist[n];
55+
}
56+
}
57+
58+
int main() {
59+
cin >> n >> m;
60+
memset(g, INFBYTE, sizeof(g));
61+
while(m--) {
62+
int x, y, z;
63+
cin >> x >> y >> z;
64+
/* repeat edge */
65+
g[x][y] = min(g[x][y], z);
66+
}
67+
cout << dijistra() << endl;
68+
return 0;
69+
}

Graph/ShortestPath/AW849_noted.cpp

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
总结起来核心就三步,肥肠煎蛋
3+
4+
首先寻找目前状态下离第一个结点距离最小的结点
5+
6+
然后将这个结点加入已经确定距离的结点中
7+
8+
接着更新状态,即加入新的结点后看看是否因为这个新加的结点而出现一条更短的距离,如果有,就更新距离
9+
*/
10+
11+
#include <iostream>
12+
#include <cstring>
13+
#include <algorithm>
14+
using namespace std;
15+
const int N = 510;
16+
int n, m;
17+
int g[N][N]; // g[ 1 ][ 2 ]是指从1节点指向2节点的距离,也可以表示不存在
18+
int dist[N]; // distance(距离)的缩写,代表每一个点到源点的距离
19+
bool st[N];
20+
// state(状态)的缩写,当st[n]为true时说明这个点到源点的距离最小值就已经确定了
21+
int dijkstra() {
22+
memset(dist, 0x3f, sizeof(dist)); // 存储每一个点到源点的距离
23+
// 比较大的数
24+
dist[1] = 0; // 源点到自己的距离为0
25+
for (int i = 0; i < n - 1; i++) {
26+
// 其实这条语句唯一的作用就是循环n-1次(优化了)
27+
// 所以写成for(int i=0;i<n;i++)也可以,
28+
// 因为如果下面的语句循环了n-1次的话,那么所有点都能得到最小值了
29+
// 可以这么理解,每次循环都会确定一个最小值,还会再创造一个最小值(留给下一次循环去确定)
30+
// 当循环n-1次时,情况是已经确定了n-1个点的最小值了,还创造了一个最小值(此时还有1个点等着下一次去确定)
31+
// 那么就不需要下一次循环了,毕竟剩下的就一个点,在1个点的集合中知道有一个点是最小值,顺理成章了
32+
// 当然你想写成for(int i=0;i<n;i++)也能AC~~小声说~~
33+
int t = -1;
34+
for (int j = 1; j <= n; j++) {
35+
if (!st[j] and (t == -1 or dist[t] > dist[j])) {
36+
t = j;
37+
//! st[j]指的是最近距离还没有确定的点,and后面就是找符合!st[j]条件的距离最小的点
38+
// 这一个操作就是找到未确定最小值的
39+
// `点集`中的最小点,t==-1是当第一次遇到未确定~的点时能够被初始化
40+
}
41+
}
42+
//(1)
43+
for (int j = 1; j <= n; j++) {
44+
// 现在找到t了,遍历一遍所有点,有一下几种情况
45+
// 1.j点和t点之间无连接,那么g[t][j]=0x3f3f3f3f,特别大,会被pass
46+
// 2.dist[j]<=dist[t]+g[t][j],源点到j点的距离,如果经过t后距离更长了,那么不考虑
47+
// 3.dist[j]<=dist[t]+g[t][j],,~~,经过t点距离更短了,那么修改dist[j]的值
48+
dist[j] = min(dist[j], dist[t] + g[t][j]);
49+
}
50+
st[t] = true;
51+
// 当前t点已经把其余点全部遍历了一遍,此点变成确定距离为最小的点了,这条语句放在(1)处也能AC
52+
}
53+
if (dist[n] == 0x3f3f3f3f) {
54+
// 当前点n没被修改,说明到不了点n,输出-1
55+
return -1;
56+
} else {
57+
return dist[n]; // 易证
58+
}
59+
}
60+
int main() {
61+
cin >> n >> m; // n存点数,m存边数
62+
memset(g, 0x3f, sizeof(g));
63+
// 将点之间的距离的每一个值设置成很大的数,此知识点之前讲过
64+
while (m--) {
65+
int a, b, c;
66+
cin >> a >> b >> c;
67+
g[a][b] = min(g[a][b], c); // 有效解决多条边的问题,保留最短边
68+
}
69+
cout << dijkstra() << endl;
70+
return 0;
71+
}

Graph/ShortestPath/AW850Dijkstra2.cpp

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
n points, m edges
3+
repeat edges, circul, weight >= 0
4+
find shortest distance between 1 and n, else -1
5+
6+
n, m <= 1.5e5
7+
normal Dijkstra: O(N^2), TLE
8+
Heap Optimization: O(m logm), for 稀疏图, 邻接表存
9+
10+
输入样例:
11+
3 3
12+
1 2 2
13+
2 3 1
14+
1 3 4
15+
输出样例:
16+
3
17+
*/
18+
19+
#include <bits/stdc++.h>
20+
using namespace std;
21+
typedef pair<int, int> PII;
22+
const int N = 1.5e5 + 10;
23+
const uint8_t INFBYTE = 0x3f;
24+
const int INFINT = 0x3f3f3f3f;
25+
26+
int firstEdge[N], endPoint[N], nextEdge[N], weight[N], idx;
27+
int dist[N];
28+
bool st[N];
29+
30+
int n, m;
31+
void add(int a, int b, int c) {
32+
weight[idx] = c;
33+
endPoint[idx] = b;
34+
nextEdge[idx] = firstEdge[a];
35+
firstEdge[a] = idx;
36+
idx++;
37+
}
38+
39+
int dijkstra() {
40+
memset(dist, INFBYTE, sizeof(dist));
41+
dist[1] = 0;
42+
priority_queue<PII, vector<PII>, greater<PII>> heap;
43+
// 这里heap中为什么要存pair呢,首先小根堆是根据距离来排的,所以有一个变量要是距离,
44+
// 其次在从堆中拿出来的时候要知道知道这个点是哪个点,不然怎么更新邻接点呢?所以第二个变量要存点。
45+
heap.push({ 0, 1 }); /* first: distance, second: point id*/
46+
while(heap.size()) {
47+
PII p = heap.top();
48+
heap.pop();
49+
int distance = p.first, cur = p.second;
50+
if(st[cur]) continue;
51+
/* mark as determined */
52+
st[cur] = true;
53+
for(auto edge = firstEdge[cur]; edge != -1; edge = nextEdge[edge]) {
54+
int end = endPoint[edge];
55+
if(dist[end] > distance + weight[edge]) {
56+
dist[end] = distance + weight[edge];
57+
heap.push({ dist[end], end });
58+
}
59+
}
60+
}
61+
if(dist[n] == INFINT) {
62+
return -1;
63+
} else {
64+
return dist[n];
65+
}
66+
}
67+
int main() {
68+
cin >> n >> m;
69+
memset(firstEdge, -1, sizeof(firstEdge));
70+
while(m--) {
71+
int x, y, z;
72+
cin >> x >> y >> z;
73+
add(x, y, z);
74+
}
75+
cout << dijkstra() << endl;
76+
}

Graph/ShortestPath/AW851SPFA.cpp

Whitespace-only changes.

Graph/ShortestPath/AW853BFord.cpp

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
3+
https://www.acwing.com/problem/content/855/
4+
5+
作者:yxc
6+
链接:https://www.acwing.com/activity/content/code/content/48523/
7+
来源:AcWing
8+
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
9+
10+
负权图最短路, 限制 k
11+
12+
输入样例:
13+
3 3 1
14+
1 2 1
15+
2 3 1
16+
1 3 3
17+
输出样例:
18+
3
19+
20+
21+
*/
22+
23+
#include <cstring>
24+
#include <iostream>
25+
#include <algorithm>
26+
27+
using namespace std;
28+
29+
const int N = 510, M = 10010;
30+
31+
struct Edge {
32+
int a, b, c;
33+
} edges[M];
34+
35+
int n, m, k;
36+
int dist[N];
37+
int last[N];
38+
39+
void bellman_ford() {
40+
memset(dist, 0x3f, sizeof dist);
41+
42+
dist[1] = 0;
43+
for (int i = 0; i < k; i++) {
44+
memcpy(last, dist, sizeof dist);
45+
for (int j = 0; j < m; j++) {
46+
auto e = edges[j];
47+
dist[e.b] = min(dist[e.b], last[e.a] + e.c);
48+
}
49+
}
50+
}
51+
52+
int main() {
53+
scanf("%d%d%d", &n, &m, &k);
54+
55+
for (int i = 0; i < m; i++) {
56+
int a, b, c;
57+
scanf("%d%d%d", &a, &b, &c);
58+
edges[i] = {a, b, c};
59+
}
60+
61+
bellman_ford();
62+
63+
if (dist[n] > 0x3f3f3f3f / 2)
64+
puts("impossible");
65+
else
66+
printf("%d\n", dist[n]);
67+
68+
return 0;
69+
}

Graph/ShortestPath/AW854Floyd.cpp

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
多源汇最短路问题-具有多个源点
3+
4+
Floyd算法 O(n^3)-动态规划
5+
6+
给定一个n个点m条边的有向图,图中可能存在重边和自环,边权可能为负数。
7+
8+
再给定k个询问,每个询问包含两个整数x和y,表示查询从点x到点y的最短距离,如果路径不存在,则输出“impossible”。
9+
10+
数据保证图中不存在负权回路。
11+
12+
作者:郡呈
13+
链接:https://www.acwing.com/solution/content/6976/
14+
来源:AcWing
15+
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
16+
*/
17+
#include <iostream>
18+
using namespace std;
19+
20+
const int N = 210, M = 2e+10, INF = 1e9;
21+
22+
int n, m, k, x, y, z;
23+
int d[N][N];
24+
25+
void floyd() {
26+
for(int k = 1; k <= n; k++)
27+
for(int i = 1; i <= n; i++)
28+
for(int j = 1; j <= n; j++)
29+
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
30+
}
31+
32+
int main() {
33+
cin >> n >> m >> k;
34+
for(int i = 1; i <= n; i++)
35+
for(int j = 1; j <= n; j++)
36+
if(i == j)
37+
d[i][j] = 0;
38+
else
39+
d[i][j] = INF;
40+
while(m--) {
41+
cin >> x >> y >> z;
42+
d[x][y] = min(d[x][y], z);
43+
// 注意保存最小的边
44+
}
45+
floyd();
46+
while(k--) {
47+
cin >> x >> y;
48+
if(d[x][y] > INF / 2) puts("impossible");
49+
// 由于有负权边存在所以约大过INF/2也很合理
50+
else
51+
cout << d[x][y] << endl;
52+
}
53+
return 0;
54+
}

0 commit comments

Comments
 (0)