对之前这篇文章《JS (node) 的 ACM 模式 + debug方法 (01背包为例)》 做一点补充。
- 以《所有可达路径》这道题为例
事件监听方式
使用 readline.on('line', callback)
逐行监听输入,将每一行存储到 input 数组中。然后再对提取出 input 中的参数做题。
需要在 readline.close()
后,手动处理输入的数据。
适用于需要一次性读取所有数据,然后再处理的场景。
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
let input = [];
readline.on('line', (line) => {
input.push(line);
});
readline.on('close', () => {
// 读取输入并初始化图
const [N, M] = input[0].split(' ').map(Number);
const graph = Array.from({ length: N + 1 }, () => Array(N + 1).fill(0));
for (let i = 1; i <= M; i++) {
const [s, t] = input[i].split(' ').map(Number);
graph[s][t] = 1;
}
let result = [];
let path = [1];
function dfs(node) {
if (node === N) {
result.push([...path]);
return;
}
for (let next = 1; next <= N; next++) {
if (graph[node][next] === 1) {
path.push(next);
dfs(next);
path.pop();
}
}
}
dfs(1);
if (result.length > 0) {
result.forEach(p => console.log(p.join(' ')));
} else {
console.log(-1);
}
});
Symbol.asyncIterator 的方式
使用异步迭代器逐行读取输入,每次调用 await iter.next()
以获取新行。
数据读取和处理可以同时进行,直接在读取过程中执行逻辑。
更加灵活,适合逐行处理输入数据,尤其是在输入数据量较大时,可以减少内存消耗。
const readline = require('readline').createInterface({ input: process.stdin });
let iter = readline[Symbol.asyncIterator]();
// 异步读取一行输入
const getLine = async () => (await iter.next()).value;
let graph; // 邻接矩阵
let N, M; // 节点数和边数
let result = []; // 保存所有路径
let path = []; // 当前路径
// 初始化邻接矩阵
async function initGraph() {
const firstLine = await getLine();
[N, M] = firstLine.split(' ').map(Number);
// 创建一个 (N+1) x (N+1) 的矩阵,初始化为 0
graph = Array.from({ length: N + 1 }, () => Array(N + 1).fill(0));
// 读取边并填充邻接矩阵
for (let i = 0; i < M; i++) {
const edge = await getLine();
const [s, t] = edge.split(' ').map(Number);
graph[s][t] = 1; // 表示从 s 到 t 有边
}
}
// 深度优先搜索
function dfs(node) {
if (node === N) {
result.push([...path]); // 找到一条路径,保存结果
return;
}
for (let next = 1; next <= N; next++) {
if (graph[node][next] === 1) { // 如果有边
path.push(next); // 添加到路径
dfs(next); // 递归搜索下一个节点
path.pop(); // 回溯
}
}
}
(async function () {
// 初始化图
await initGraph();
// 从节点 1 开始搜索
path.push(1);
dfs(1);
// 输出结果
if (result.length > 0) {
result.forEach(p => console.log(p.join(' ')));
} else {
console.log(-1); // 如果没有路径
}
readline.close();
})();
补充 readline
通过 readline 读取的 input 中的每一行默认都是字符串类型。无论输入的是数字、字母还是其他字符,最终都会以 字符串 的形式存储在 input 中。
- 例
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
let input = [];
readline.on('line', (line) => {
input.push(line);
});
readline.on('close', () => {
console.log(input); // 打印 input 的内容
});
如果输入
5 5
1 3
3 5
1 2
2 4
4 5
那么输出
[
'5 5',
'1 3',
'3 5',
'1 2',
'2 4',
'4 5'
]
如果需要将字符串解析成数字或其他类型,需要手动转换。例如:
const [a, b] = '5 5'.split(' ').map(Number);
// 转换为数字数组 [5, 5]
input.split(' ') 将字符串 "5 10" 按空格分割成数组:['5', '10']。
.map(Number) 将数组中的每个字符串转换为数字:[5, 10]。
[a, b] 解构数组,将 5 赋值给 a,10 赋值给 b。