1 番から n 番までの選手 n 人が競走に出て、同じ順位はない。 手がかりが m 個与えられ、手がかり "a b" は a 番の選手が b 番の選手より先にゴールしたという意味である。 同じ手がかりが何度も与えられることがあり、手がかり同士が食い違うこともある。 手がかりだけを見て、1 位から順に順位を決めていく。 まだ順位が決まっていない選手のうち、自分より先にゴールしたと書かれた選手が全員すでに順位が決まっている選手を候補と呼ぶ。 自分より先にゴールしたという手がかりが一つもない選手も候補である。 候補がちょうど一人なら、その選手が次の順位になり、残りの選手で同じことを繰り返す。 候補がいないか二人以上なら、そこで止まる。 全員の順位が決まっても止まる。 一行目に、順位が決まった選手の番号を 1 位から順に出力せよ。 二行目に、止まったときの候補の番号を小さい順に出力せよ。
入力
一行目に n と m が空白一つで区切られて与えられる。 続く m 行には各行に a と b が空白一つで区切られて与えられる。 1 ≤ n ≤ 50、0 ≤ m ≤ 200、1 ≤ a, b ≤ n、a ≠ b
import sysdata = sys.stdin.read().split()n, m = int(data[0]), int(data[1])after = [[] for _ in range(n + 1)] # after[a] = a보다 늦게 들어왔다고 적힌 선수들waiting = [0] * (n + 1) # 아직 등수가 안 정해진 '앞선 선수' 단서의 수for i in range(m): a, b = int(data[2 + 2 * i]), int(data[3 + 2 * i]) after[a].append(b) # 같은 단서가 또 나오면 또 넣고 waiting[b] += 1 # 또 센다(둘이 늘 맞는다)placed = [False] * (n + 1)order = []while True: cand = [v for v in range(1, n + 1) if not placed[v] and waiting[v] == 0] if len(cand) != 1: # 후보가 없거나 여럿이면 멈춘다 break v = cand[0] placed[v] = True order.append(v) for b in after[v]: waiting[b] -= 1# " ".join([])은 빈 문자열이라 빈 목록은 따로 "-"로 쓴다print(" ".join(map(str, order)) if order else "-")print(" ".join(map(str, cand)) if cand else "-")
JavaScriptmain.js · 26 行
const data = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [n, m] = data;// fill([])은 같은 배열 하나를 모든 칸에 넣으니 칸마다 새 배열을 만든다const after = Array.from({ length: n + 1 }, () => []); // after[a] = a보다 늦게 들어왔다고 적힌 선수들const waiting = new Array(n + 1).fill(0); // 아직 등수가 안 정해진 '앞선 선수' 단서의 수for (let i = 0; i < m; i++) { const a = data[2 + 2 * i], b = data[3 + 2 * i]; after[a].push(b); waiting[b]++;}const placed = new Array(n + 1).fill(false);const order = [];let cand = [];while (true) { cand = []; for (let v = 1; v <= n; v++) if (!placed[v] && waiting[v] === 0) cand.push(v); if (cand.length !== 1) break; // 후보가 없거나 여럿이면 멈춘다 const v = cand[0]; placed[v] = true; order.push(v); for (const b of after[v]) waiting[b]--;}console.log(order.length ? order.join(" ") : "-");console.log(cand.length ? cand.join(" ") : "-");
TypeScriptmain.ts · 26 行
const data: number[] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [n, m] = data;// fill([])은 같은 배열 하나를 모든 칸에 넣으니 칸마다 새 배열을 만든다const after: number[][] = Array.from({ length: n + 1 }, () => []); // after[a] = a보다 늦게 들어왔다고 적힌 선수들const waiting: number[] = new Array(n + 1).fill(0); // 아직 등수가 안 정해진 '앞선 선수' 단서의 수for (let i = 0; i < m; i++) { const a = data[2 + 2 * i], b = data[3 + 2 * i]; after[a].push(b); waiting[b]++;}const placed: boolean[] = new Array(n + 1).fill(false);const order: number[] = [];let cand: number[] = [];while (true) { cand = []; for (let v = 1; v <= n; v++) if (!placed[v] && waiting[v] === 0) cand.push(v); if (cand.length !== 1) break; // 후보가 없거나 여럿이면 멈춘다 const v = cand[0]; placed[v] = true; order.push(v); for (const b of after[v]) waiting[b]--;}console.log(order.length ? order.join(" ") : "-");console.log(cand.length ? cand.join(" ") : "-");
JavaMain.java · 43 行
import java.util.*;public class Main { // 수 목록을 빈칸으로 이어 쓴다(비었으면 "-") static String show(List<Integer> list) { if (list.isEmpty()) return "-"; StringBuilder sb = new StringBuilder(); for (int v : list) { if (sb.length() > 0) sb.append(' '); sb.append(v); } return sb.toString(); } public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(), m = in.nextInt(); List<List<Integer>> after = new ArrayList<>(); // after.get(a) = a보다 늦게 들어왔다고 적힌 선수들 for (int v = 0; v <= n; v++) after.add(new ArrayList<>()); int[] waiting = new int[n + 1]; // 아직 등수가 안 정해진 '앞선 선수' 단서의 수 for (int i = 0; i < m; i++) { int a = in.nextInt(), b = in.nextInt(); after.get(a).add(b); waiting[b]++; } boolean[] placed = new boolean[n + 1]; List<Integer> order = new ArrayList<>(); List<Integer> cand; while (true) { cand = new ArrayList<>(); for (int v = 1; v <= n; v++) if (!placed[v] && waiting[v] == 0) cand.add(v); if (cand.size() != 1) break; // 후보가 없거나 여럿이면 멈춘다 int v = cand.get(0); placed[v] = true; order.add(v); for (int b : after.get(v)) waiting[b]--; } System.out.println(show(order)); System.out.println(show(cand)); }}
C#Main.cs · 38 行
using System;using System.Collections.Generic;class Program{ static void Main() { var data = Console.In.ReadToEnd().Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); int n = int.Parse(data[0]), m = int.Parse(data[1]); var after = new List<int>[n + 1]; // after[a] = a보다 늦게 들어왔다고 적힌 선수들 for (int v = 0; v <= n; v++) after[v] = new List<int>(); // 칸마다 new를 해야 한다(처음에는 null) var waiting = new int[n + 1]; // 아직 등수가 안 정해진 '앞선 선수' 단서의 수 for (int i = 0; i < m; i++) { int a = int.Parse(data[2 + 2 * i]), b = int.Parse(data[3 + 2 * i]); after[a].Add(b); waiting[b]++; } var placed = new bool[n + 1]; var order = new List<int>(); List<int> cand; while (true) { cand = new List<int>(); for (int v = 1; v <= n; v++) if (!placed[v] && waiting[v] == 0) cand.Add(v); if (cand.Count != 1) break; // 후보가 없거나 여럿이면 멈춘다 int w = cand[0]; placed[w] = true; order.Add(w); foreach (int b in after[w]) waiting[b]--; } // string.Join은 수 목록도 바로 이어 준다 Console.WriteLine(order.Count > 0 ? string.Join(" ", order) : "-"); Console.WriteLine(cand.Count > 0 ? string.Join(" ", cand) : "-"); }}
C++main.cpp · 43 行
#include <iostream>#include <vector>using namespace std;// 수 목록을 빈칸으로 이어 쓴다(비었으면 "-")void show(const vector<int>& list) { if (list.empty()) cout << "-"; for (size_t i = 0; i < list.size(); i++) { if (i > 0) cout << ' '; cout << list[i]; } cout << '\n';}int main() { int n, m; cin >> n >> m; vector<vector<int>> after(n + 1); // after[a] = a보다 늦게 들어왔다고 적힌 선수들(칸마다 따로 있는 빈 vector) vector<int> waiting(n + 1, 0); // 아직 등수가 안 정해진 '앞선 선수' 단서의 수 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; after[a].push_back(b); waiting[b]++; } vector<bool> placed(n + 1, false); vector<int> order, cand; while (true) { cand.clear(); for (int v = 1; v <= n; v++) if (!placed[v] && waiting[v] == 0) cand.push_back(v); if (cand.size() != 1) break; // 후보가 없거나 여럿이면 멈춘다 int v = cand[0]; placed[v] = true; order.push_back(v); for (int b : after[v]) waiting[b]--; } show(order); show(cand); return 0;}
Cmain.c · 41 行
#include <stdio.h>#define MAXN 50#define MAXM 200// 수 k개를 빈칸으로 이어 쓴다(없으면 "-")void show(const int *a, int k) { if (k == 0) printf("-"); for (int i = 0; i < k; i++) printf(i ? " %d" : "%d", a[i]); printf("\n");}int main(void) { int n, m; if (scanf("%d %d", &n, &m) != 2) return 0; int from[MAXM], to[MAXM]; // 단서를 그대로 적어 둔다(같은 단서도 그대로) int waiting[MAXN + 1] = {0}; // 아직 등수가 안 정해진 '앞선 선수' 단서의 수 for (int i = 0; i < m; i++) { scanf("%d %d", &from[i], &to[i]); waiting[to[i]]++; } int placed[MAXN + 1] = {0}; int order[MAXN], cand[MAXN]; int count = 0, k = 0; while (1) { k = 0; for (int v = 1; v <= n; v++) if (!placed[v] && waiting[v] == 0) cand[k++] = v; if (k != 1) break; // 후보가 없거나 여럿이면 멈춘다 int v = cand[0]; placed[v] = 1; order[count++] = v; for (int i = 0; i < m; i++) if (from[i] == v) waiting[to[i]]--; } show(order, count); show(cand, k); return 0;}
Craykonmain.cray · 57 行
// 수 목록을 빈칸으로 이어 쓴다(비었으면 "-")보여주기(list){ もし (list.個数 == 0) { コンソール.書く("-"); } でなければ { コンソール.書く(list); // 목록을 쓰면 빈칸으로 이어 쓴다 }}첫줄 = コンソール.数読み();n = 첫줄[0];m = 첫줄[1];after = []; // after[a] = a보다 늦게 들어왔다고 적힌 선수들繰り返す (v = 0; v <= n; v++){ after.追加([]); // 칸마다 새 목록을 만든다}waiting = 新リスト(n + 1, 0); // 아직 등수가 안 정해진 '앞선 선수' 단서의 수繰り返す (i = 0; i < m; i++){ 쌍 = コンソール.数読み(); after[쌍[0]].追加(쌍[1]); waiting[쌍[1]] += 1;}placed = 新リスト(n + 1, 偽);order = [];cand = [];間 (真){ cand = []; 繰り返す (v = 1; v <= n; v++) { もし (!placed[v] && waiting[v] == 0) { cand.追加(v); } } もし (cand.個数 != 1) { 抜ける; // 후보가 없거나 여럿이면 멈춘다 } w = cand[0]; placed[w] = 真; order.追加(w); それぞれ (b の中 after[w]) { waiting[b] -= 1; }}보여주기(order);보여주기(cand);