@@ -254,6 +254,119 @@ int main() {
254254
255255### Javascript
256256
257+ ``` javascript
258+ const r1 = require (' readline' ).createInterface ({ input: process .stdin });
259+ // 创建readline接口
260+ let iter = r1[Symbol .asyncIterator ]();
261+ // 创建异步迭代器
262+ const readline = async () => (await iter .next ()).value ;
263+
264+
265+ let N // 节点数和边数
266+ let father = [] // 并查集
267+ let edges = [] // 边集
268+ let inDegree = [] // 入度
269+
270+
271+ // 并查集初始化
272+ const init = () => {
273+ for (let i = 1 ; i <= N ; i++ ) father[i] = i;
274+ }
275+
276+ // 并查集里寻根的过程
277+ const find = (u ) => {
278+ return u == father[u] ? u : father[u] = find (father[u])
279+ }
280+
281+ // 将v->u 这条边加入并查集
282+ const join = (u , v ) => {
283+ u = find (u)
284+ v = find (v)
285+ if (u == v) return // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
286+ father[v] = u
287+ }
288+
289+ // 判断 u 和 v是否找到同一个根
290+ const isSame = (u , v ) => {
291+ u = find (u)
292+ v = find (v)
293+ return u == v
294+ }
295+
296+ // 判断删除一条边后是不是树
297+ const isTreeAfterRemoveEdge = (edges , edge ) => {
298+ // 初始化并查集
299+ init ()
300+
301+ for (let i = 0 ; i < N ; i++ ) {
302+ if (i == edge) continue
303+ if (isSame (edges[i][0 ], edges[i][1 ])) { // 构成有向环了,一定不是树
304+ return false
305+ }
306+ join (edges[i][0 ], edges[i][1 ])
307+ }
308+ return true
309+ }
310+
311+ // 在有向图里找到删除的那条边, 使其成为树
312+ const getRemoveEdge = (edges ) => {
313+ // 初始化并查集
314+ init ()
315+
316+ for (let i = 0 ; i < N ; i++ ) {
317+ if (isSame (edges[i][0 ], edges[i][1 ])) { // 构成有向环了,就是要删除的边
318+ console .log (edges[i][0 ], edges[i][1 ]);
319+ return
320+ } else {
321+ join (edges[i][0 ], edges[i][1 ])
322+ }
323+ }
324+ }
325+
326+
327+ (async function () {
328+ // 读取第一行输入
329+ let line = await readline ();
330+ N = Number (line);
331+
332+ // 读取边信息, 统计入度
333+ for (let i = 0 ; i < N ; i++ ) {
334+ line = await readline ()
335+ line = line .split (' ' ).map (Number )
336+
337+ edges .push (line)
338+
339+ inDegree[line[1 ]] = (inDegree[line[1 ]] || 0 ) + 1
340+ }
341+
342+ // 找到入度为2的节点
343+ let vec = [] // 记录入度为2的边(如果有的话就两条边)
344+ // 找入度为2的节点所对应的边,注意要倒序,因为优先删除最后出现的一条边
345+ for (let i = N - 1 ; i >= 0 ; i-- ) {
346+ if (inDegree[edges[i][1 ]] == 2 ) {
347+ vec .push (i)
348+ }
349+ }
350+
351+ // 情况一、情况二
352+ if (vec .length > 0 ) {
353+ // 放在vec里的边已经按照倒叙放的,所以这里就优先删vec[0]这条边
354+ if (isTreeAfterRemoveEdge (edges, vec[0 ])) {
355+ console .log (edges[vec[0 ]][0 ], edges[vec[0 ]][1 ]);
356+ } else {
357+ console .log (edges[vec[1 ]][0 ], edges[vec[1 ]][1 ]);
358+ }
359+ return 0
360+ }
361+
362+ // 情况三
363+ // 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
364+ getRemoveEdge (edges)
365+ })()
366+ ```
367+
368+
369+
257370### TypeScript
258371
259372### PhP
0 commit comments