题面


此题看似是一道图论,实则比较基础。
只要掌握了基础的 DFS/BFS 即可爆切本题。

具体思路

0x01 读题分析

  • 请帮助小 K 设计一种方法,使小 K 可以不重复、不遗漏的看完所有他能看到的文章。
  • 对图分别进行 DFSBFS,并输出遍历结果。

读到这两句话,我们就可以很清楚地知道此题考点:搜索和图论(有向图遍历)。

有一个小小的细节:

如果有很多篇文章可以参阅,请先看编号较小的那篇(因此你可能需要先排序)。

事实上这句话就相当于告诉了我们搜索的优先顺序,即从小到大搜。

0x02 输入和排序

根据上面分析,如果需要排序每一个结点的所有路径,可以使用 vector 数组。
这样的方式比较简单:

// 存储:vector 数组
vector <int> maps[int(1e5) + 1];
// 输入:u 为起点,v 为终点
maps[u].push_back(v);
// 排序:对编号为 i 的每一个结点的路径排序
sort(maps[i].begin(), maps[i].end());

我们可以写出以下程序,实现输入数据和排序:

cin >> n >> m; // 输入 n, m
for(int i = 1; i <= m; i++){
    int u, v;
    cin >> u >> v; // 输入每一条路径
    maps[u].push_back(v); // 离线存储
}
for(int i = 1; i <= n; i++){
	sort(maps[i].begin(), maps[i].end());
}

0x03 DFS

void dfs(int k = 1){ // k:当前遍历的结点编号
	cout << k << " "; // 输出即可
	for(auto i : maps[k]){ // 遍历:以 k 为起点,每一条路径的终点
		if(!vis[i]){ // 如果没访问过就递归(不重复访问)
			vis[i] = true;
			dfs(i);
		}
	}
}

0x04 BFS

void bfs(){
	queue <int> Q;
	vis[1] = true;
	Q.push(1); // 起点入队
	while(!Q.empty()){
		int fr = Q.front(); Q.pop();
		cout << fr << " "; // 输出当前位置
		for(auto i : maps[fr]){ // 遍历:每一条路径
			if(!vis[i]){ // 没访问过
				vis[i] = true;
				Q.push(i);
			}
		}
	}
}

0x05 完整程序

// Author:PanDaoxi
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

int n, m;
vector <int> maps[int(1e5) + 1];
bool vis[int(1e5) + 1] = {false, true};

void dfs(int k = 1){
	cout << k << " ";
	for(auto i : maps[k]){
		if(!vis[i]){
			vis[i] = true;
			dfs(i);
		}
	}
}

void bfs(){
	cout << endl;
	queue <int> Q;
	memset(vis, 0, sizeof(vis));
	vis[1] = true;
	Q.push(1);
	while(!Q.empty()){
		int fr = Q.front(); Q.pop();
		cout << fr << " ";
		for(auto i : maps[fr]){
			if(!vis[i]){
				vis[i] = true;
				Q.push(i);
			}
		}
	}
}

int main(){
	ios :: sync_with_stdio(false);

    cin >> n >> m;
    for(int i = 1; i <= m; i++){
        int u, v;
        cin >> u >> v;
        maps[u].push_back(v);
    }
    for(int i = 1; i <= n; i++){
		sort(maps[i].begin(), maps[i].end());
	}
	dfs();
	bfs();

	return 0;
}