P5318 【深基18.例3】查找文献

这题是分别进行DFS和BFS遍历,要求有多个节点时,按照从小到大进行排序。由于采用的是yxc的链式前向星存储,涉及到多个数组,不知道该如何在输入后立即进行排序。因此第一次我多次在遍历过程中使用set来进行排序。功能正确但是会超时。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <cstring>
#include <iostream>
#include <queue>
#include <set>

using namespace std;

const int N = 1e5 + 5;
int n, m;

int h[N], e[N], ne[N], idx = 0;
bool st[N]; // 标记数组

void add(int a, int b) {
e[idx] = b; // 添加边 b
ne[idx] = h[a];
h[a] = idx++;
}

void dfs(int u) {
set<int> set_save; // 每次递归调用时使用一个新的 set
st[u] = true;
cout << u << " ";
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
set_save.insert(j);
}
}
for (int j : set_save) {
dfs(j);
}
}

void bfs(int u) {
priority_queue<int> que;
que.push(u);
st[u] = true;
while (!que.empty()) {
int t = que.top();
que.pop();
cout << t << " ";
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
st[j] = true;
que.push(j);
}
}
}
}

int main() {
int a, b;
cin >> n >> m;
memset(h, -1, sizeof(h));
for (int i = 0; i < m; i++) {
cin >> a >> b;
add(a, b);
}

memset(st, 0, sizeof(st));

dfs(1);
cout << endl;

memset(st, 0, sizeof(st));

bfs(1);
cout << endl;

return 0;
}

在搜索途中发现查找文献 (yuque.com),我们其实是可以对输入进行排序的,首先要创建存储x,y的节点,将输入存储进去。

接下来是排序:

  1. 对于x,母庸置疑,我们将较小值置前。
  2. 对于y,较小值置前? 不是。链式前向星中h[a]存储的是第一条边的索引,且该索引能被覆盖。因此我们应该倒序存储,这样才能使h[a]存储的是最小值的边。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// 

#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <set>
#include <vector>
using namespace std;

const int N = 1e6 + 5;
int n, m;

int h[N], e[N], ne[N], idx = 0;
bool st[N]; // 标记数组

struct nod {
int x, y;
} node[N];

void add(int a, int b) {
e[idx] = b; // 添加边 b
ne[idx] = h[a]; //下一条边的索引
h[a] = idx++; //该节点第一条边的索引
}

void dfs(int u) {
st[u] = true;
cout << u << " ";
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
dfs(j);
}
}
}

void bfs(int u) {
queue<int> que;
que.push(u);
st[u] = true;
while (!que.empty()) {
int t = que.front();
que.pop();
cout << t << " ";
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
st[j] = true;
que.push(j);
}
}
}
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
memset(h, -1, sizeof(h));
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
node[i].x = a;
node[i].y = b;
}
sort(node, node + m, [](nod a, nod b) {
if (a.x != b.x) {
return a.x < b.x;
} else {
return a.y > b.y; //由于h[a]的idx会被最后一条idx覆盖,因此我们应该倒序存储
}
});

for (int i = 0; i < m; i++) {
add(node[i].x, node[i].y);
}

memset(st, 0, sizeof(st)); // 初始化标记数组

dfs(1);
cout << endl;

memset(st, 0, sizeof(st)); // 重新初始化标记数组

bfs(1);
cout << endl;

return 0;
}

P3916 图的遍历

这题采用反向建边的方法,即从最大的点到最小的点,依次进行深度优先搜索,最后得出的st数组即为该点能达到的最大值。而不需要对每条边都进行深搜且将st数组置0。