题目链接:P5318 【深基18.例3】查找文献
补:输入格式
第一行两个整数 (n, m)。
接下来 (m) 行,每行两个整数 (X, Y),表示文章 (X) 有参考文献 (Y)。
(其实这题的 (n) 并没有什么卵用……)
补:输出格式
(2) 行,每行(n) 个整数,表示遍历的顺序。
审题&解法
这题就是给一张图,让你求对它进行深度优先搜索(DFS)和广度优先搜索的(BFS)遍历的顺序。当然是用邻接表来存图。
这题的难点(我认为的难点)在于这:
如果有很多篇文章可以参阅,请先看编号较小的那篇
我们必须先看编号小的,否则输出结果就不能正确。
尽管题目的样例是排好了序的,但是题目描述中并没有保证输入的数据一定是有序的,而且因为邻接表最后加的边会最先访问,最早加的边会最后访问,我们需要以head[]
数组为第一关键字从小到大排序,以to[]
数组为第二关键字从大到小排序。
使用结构体和sort()
,再借助cmp()
就可以完成排序。
排序的cmp()
函数如下:
bool cmp(node a, node b) {
if (a.from == b.from) return a.to > b.to;
return a.from < b.from;
}
如果没看懂就好好理解一下。
代码
#include <cstdio>
#include <iostream>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
struct node {
int from, to, nxt;
}a[1000006];
int head[100005], d[100005];
bool vis[100005];
int tot;
bool cmp(node a, node b) {
if (a.from == b.from) return a.to > b.to; //如果两个的from[]相等,就按to从大到小排序
return a.from < b.from; //否则按from从小到大排序
}
inline void add(int x, int y) {
a[++tot].to = y;
a[tot].nxt = head[x], head[x] = tot;
}
inline int read() {
int X = 0; bool flag = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') flag = 0; ch = getchar();}
while (ch >= '0' && ch <= '9') {X = (X << 1) + (X << 3) + ch - '0'; ch = getchar();}
if (flag) return X;
return ~ (X - 1);
}
inline void write(int X) {
if (X < 0) {putchar('-'); X = ~ (X - 1);}
int s[50], top = 0;
while (X) {s[++top] = X % 10; X /= 10;}
if (!top) s[++top] = 0;
while (top) putchar(s[top--] + '0');
putchar(' ');
return;
}
void dfs(int x) {
write(x);
vis[x] = true; //标记到过
for (int i = head[x]; i; i = a[i].nxt) { //循环出边
if (!vis[a[i].to]) //如果没到过
dfs(a[i].to); //就搜索它
}
return;
}
void bfs() { //广搜
queue<int> que; //先定义一个队列
que.push(1); d[1] = 1; //将1加入队列
while (!que.empty()) { //循环,直到队列为空
int x = que.front(); que.pop(); //从队头取出一个值,把它弹出
write(x); //把它输出
for (int i = head[x]; i; i = a[i].nxt) { //循环他的每一条出边,如果没有访问过,就把它加入队列
int y = a[i].to;
if (d[y]) continue;
d[a[i].to] = 1; //标记它被访问过(本来存深度,但在这题它退化了),本来应该为d[y] = d[x] + 1;
que.push(y); //将加入队列
}
}
}
signed main() {
int m;
m = read(); m = read();
for (int i = 1; i <= m; i++) { //先在结构体里输入,但不加边
a[i].from = read(); a[i].to = read();
}
sort(a + 1, a + m + 1, cmp); //输入完之后排序
for (int i = 1; i <= m; i++) { //排完序之后加边,
add(a[i].from, a[i].to); //这样可以保证先搜索到的一定是编号最小的
}
dfs(1); //从1开始深搜
putchar('
'); //输出完深搜的就换行
bfs(); //广搜
putchar('
');
return 0;
}