A department has n courses numbered 1 to n, and semesters are counted 1, 2, 3, ….
Each course is offered only in certain semesters.
A course of type 0 is offered every semester, type 1 only in odd semesters (1, 3, 5, …), and type 2 only in even semesters (2, 4, 6, …).
There are m prerequisite rules, and a rule "a b" means course b can be taken only after the semester in which course a was taken has ended.
The same rule may be given more than once.
There is no limit on how many courses you take in one semester, and every course is taken in the earliest semester it can be.
That is, let L be the latest semester among the semesters in which a course's prerequisites are taken (L = 0 if it has none); the course is taken in the earliest semester after L in which it is offered.
The rules may form a cycle, so some courses may never be takeable.
A course in a cycle, and any course that requires such a course first, cannot be taken.
The first line gives n and m, and the second line gives the n types of courses 1 to n, separated by spaces.
The next m lines each give a and b separated by a space.
On the first line print the semester of courses 1 to n, separated by spaces. Print -1 for a course that cannot be taken.
On the second line print the number of semesters needed to take every takeable course, that is, the largest semester on the first line. If no course can be taken, print 0.
Input
1 ≤ n ≤ 10,000, 0 ≤ m ≤ 10,000, each type is 0, 1 or 2, 1 ≤ a, b ≤ n, a ≠ b
Output
two lines: the semester of each course (-1 if it cannot be taken), then the number of semesters needed
Example 1 · stdin
7 6
2 0 1 0 0 0 2
1 2
2 3
1 3
4 5
5 4
5 6
stdout
2 3 5 -1 -1 -1 2
5
main.py
Error List00F8 ↓ · ⇧F8 ↑
Input (stdin)
When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).
$ Ready
Open this on a computer to write and run code. On mobile you can read the problem and the solutions.
In other languagesShow solutions by language · 8 languages
Count how many prerequisites each course still has left (waiting), put the courses that reach 0 into a queue and take them out in order: a topological sort (Kahn's algorithm). When a course is taken out, all its prerequisites are done, so its semester can be fixed. Start from earliest, the earliest semester allowed by the prerequisites alone, and if the course is not offered in that semester, push it back one semester (ask about odd or even with t % 2). Then raise earliest of each following course to max(current, this course's semester + 1). Queues differ by language: Python has collections.deque with popleft() (a list's pop(0) shifts everything forward each time and is slow), Java ArrayDeque, C# Queue<int>, C++ std::queue; JS and TS have no queue and shift() is slow too, so only push into an array and move a head index head. C uses an array with head and tail indexes, and Craykon also only uses add on a list and moves head. Keeping a list of following courses differs too: Python [[] for _ in range(n + 1)] ([[]] * (n + 1) points at one single list n+1 times), Java List<List<Integer>>, and C links them with three arrays head, next, to. Five traps: ① Setting the semester from the first prerequisite that reaches a course is wrong. With 1→2→3 and 1→3, course 3 must come after course 2. Always take the latest prerequisite. ② If you fill the semesters with 0, courses that are never taken out because of a cycle stay 0. Fill with -1 or check separately. ③ A recursion that walks back through prerequisites loops forever in a cycle, and on a 10,000-step chain it exceeds Python's recursion limit (1,000 by default) and stops (Craykon also goes only about 3,000 deep). ④ If repeated rules are linked only once in the following-course list (as a set) while waiting is counted per line, that course's waiting never reaches 0 and it becomes -1. Count both the same way. ⑤ Pass the value that was pushed back to fit the offered semesters on to the following courses. If you compute all semesters ignoring the offerings and only fix odd/even per course at the end, a course after a pushed-back course comes out one semester too early. A course with no prerequisites is also in semester 2, not 1, when its type is 2.
Pythonmain.py · 36 lines
import sysfrom collections import dequedef first_open(t, kind): """t학기부터 세어 그 과목이 열리는 가장 이른 학기""" if (kind == 1 and t % 2 == 0) or (kind == 2 and t % 2 == 1): return t + 1 return tdata = sys.stdin.buffer.read().split()n, m = int(data[0]), int(data[1])kind = [0] + [int(x) for x in data[2:2 + n]] # 0: 모든 학기, 1: 홀수 학기, 2: 짝수 학기after = [[] for _ in range(n + 1)] # after[a] = a를 들어야 들을 수 있는 과목들waiting = [0] * (n + 1) # 아직 듣지 않은 선수 과목의 수for i in range(m): a, b = int(data[2 + n + 2 * i]), int(data[3 + n + 2 * i]) after[a].append(b) waiting[b] += 1earliest = [1] * (n + 1) # 선수 과목만 보면 들을 수 있는 가장 이른 학기term = [-1] * (n + 1) # 끝까지 -1이면 고리 때문에 들을 수 없다q = deque(v for v in range(1, n + 1) if waiting[v] == 0)while q: a = q.popleft() term[a] = first_open(earliest[a], kind[a]) # 선수 과목을 다 들었으니 이제 학기가 정해진다 for b in after[a]: # 선수 과목 가운데 가장 늦은 것의 다음 학기 earliest[b] = max(earliest[b], term[a] + 1) waiting[b] -= 1 if waiting[b] == 0: q.append(b)print(" ".join(map(str, term[1:])))print(max([0] + term[1:])) # 들을 수 있는 과목이 없으면 0
JavaScriptmain.js · 35 lines
const data = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [n, m] = data;const kind = [0, ...data.slice(2, 2 + n)]; // 0: 모든 학기, 1: 홀수 학기, 2: 짝수 학기// t학기부터 세어 그 과목이 열리는 가장 이른 학기function firstOpen(t, k) { if ((k === 1 && t % 2 === 0) || (k === 2 && t % 2 === 1)) return t + 1; return t;}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 + n + 2 * i], b = data[3 + n + 2 * i]; after[a].push(b); waiting[b]++;}const earliest = new Array(n + 1).fill(1); // 선수 과목만 보면 들을 수 있는 가장 이른 학기const term = new Array(n + 1).fill(-1); // 끝까지 -1이면 고리 때문에 들을 수 없다const queue = [];for (let v = 1; v <= n; v++) if (waiting[v] === 0) queue.push(v);// shift()는 매번 앞을 당겨 느리니 머리 번호 head로 꺼낸다for (let head = 0; head < queue.length; head++) { const a = queue[head]; term[a] = firstOpen(earliest[a], kind[a]); // 선수 과목을 다 들었으니 이제 학기가 정해진다 for (const b of after[a]) { earliest[b] = Math.max(earliest[b], term[a] + 1); // 가장 늦은 선수 과목의 다음 학기 if (--waiting[b] === 0) queue.push(b); }}const terms = term.slice(1);console.log(terms.join(" "));console.log(terms.reduce((x, y) => Math.max(x, y), 0));
TypeScriptmain.ts · 36 lines
import { readFileSync } from "node:fs";const data: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const n = data[0], m = data[1];const kind: number[] = [0, ...data.slice(2, 2 + n)]; // 0: 모든 학기, 1: 홀수 학기, 2: 짝수 학기// t학기부터 세어 그 과목이 열리는 가장 이른 학기function firstOpen(t: number, k: number): number { if ((k === 1 && t % 2 === 0) || (k === 2 && t % 2 === 1)) return t + 1; return t;}const after: number[][] = Array.from({ length: n + 1 }, () => []); // after[a] = a를 들어야 들을 수 있는 과목들const waiting: number[] = new Array<number>(n + 1).fill(0); // 아직 듣지 않은 선수 과목의 수for (let i = 0; i < m; i++) { const a = data[2 + n + 2 * i], b = data[3 + n + 2 * i]; after[a].push(b); waiting[b]++;}const earliest: number[] = new Array<number>(n + 1).fill(1); // 선수 과목만 보면 들을 수 있는 가장 이른 학기const term: number[] = new Array<number>(n + 1).fill(-1); // 끝까지 -1이면 고리 때문에 들을 수 없다const queue: number[] = [];for (let v = 1; v <= n; v++) if (waiting[v] === 0) queue.push(v);for (let head = 0; head < queue.length; head++) { const a = queue[head]; term[a] = firstOpen(earliest[a], kind[a]); // 선수 과목을 다 들었으니 이제 학기가 정해진다 for (const b of after[a]) { earliest[b] = Math.max(earliest[b], term[a] + 1); // 가장 늦은 선수 과목의 다음 학기 if (--waiting[b] === 0) queue.push(b); }}const terms = term.slice(1);console.log(terms.join(" "));console.log(terms.reduce((x, y) => Math.max(x, y), 0));
JavaMain.java · 61 lines
import java.io.*;import java.util.*;public class Main { // t학기부터 세어 그 과목이 열리는 가장 이른 학기(kind 0: 모든 학기, 1: 홀수 학기, 2: 짝수 학기) static int firstOpen(int t, int kind) { if ((kind == 1 && t % 2 == 0) || (kind == 2 && t % 2 == 1)) return t + 1; return t; } public static void main(String[] args) throws IOException { StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); st.nextToken(); int n = (int) st.nval; st.nextToken(); int m = (int) st.nval; int[] kind = new int[n + 1]; for (int v = 1; v <= n; v++) { st.nextToken(); kind[v] = (int) st.nval; } 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++) { st.nextToken(); int a = (int) st.nval; st.nextToken(); int b = (int) st.nval; after.get(a).add(b); waiting[b]++; } int[] earliest = new int[n + 1]; // 선수 과목만 보면 들을 수 있는 가장 이른 학기 Arrays.fill(earliest, 1); int[] term = new int[n + 1]; Arrays.fill(term, -1); // 끝까지 -1이면 고리 때문에 들을 수 없다 ArrayDeque<Integer> q = new ArrayDeque<>(); for (int v = 1; v <= n; v++) { if (waiting[v] == 0) q.add(v); } while (!q.isEmpty()) { int a = q.poll(); term[a] = firstOpen(earliest[a], kind[a]); // 선수 과목을 다 들었으니 이제 학기가 정해진다 for (int b : after.get(a)) { earliest[b] = Math.max(earliest[b], term[a] + 1); // 가장 늦은 선수 과목의 다음 학기 if (--waiting[b] == 0) q.add(b); } } StringBuilder sb = new StringBuilder(); int most = 0; for (int v = 1; v <= n; v++) { if (v > 1) sb.append(' '); sb.append(term[v]); most = Math.max(most, term[v]); } sb.append('\n').append(most).append('\n'); System.out.print(sb); }}
C#Main.cs · 61 lines
using System;using System.Collections.Generic;using System.Text;class Program{ // t학기부터 세어 그 과목이 열리는 가장 이른 학기(kind 0: 모든 학기, 1: 홀수 학기, 2: 짝수 학기) static int FirstOpen(int t, int kind) { if ((kind == 1 && t % 2 == 0) || (kind == 2 && t % 2 == 1)) return t + 1; return t; } 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 kind = new int[n + 1]; for (int v = 1; v <= n; v++) kind[v] = int.Parse(data[1 + v]); var after = new List<int>[n + 1]; // after[a] = a를 들어야 들을 수 있는 과목들 for (int v = 0; v <= n; v++) after[v] = new List<int>(); var waiting = new int[n + 1]; // 아직 듣지 않은 선수 과목의 수 for (int i = 0; i < m; i++) { int a = int.Parse(data[2 + n + 2 * i]), b = int.Parse(data[3 + n + 2 * i]); after[a].Add(b); waiting[b]++; } var earliest = new int[n + 1]; // 선수 과목만 보면 들을 수 있는 가장 이른 학기 Array.Fill(earliest, 1); var term = new int[n + 1]; Array.Fill(term, -1); // 끝까지 -1이면 고리 때문에 들을 수 없다 var q = new Queue<int>(); for (int v = 1; v <= n; v++) { if (waiting[v] == 0) q.Enqueue(v); } while (q.Count > 0) { int a = q.Dequeue(); term[a] = FirstOpen(earliest[a], kind[a]); // 선수 과목을 다 들었으니 이제 학기가 정해진다 foreach (int b in after[a]) { earliest[b] = Math.Max(earliest[b], term[a] + 1); // 가장 늦은 선수 과목의 다음 학기 if (--waiting[b] == 0) q.Enqueue(b); } } var sb = new StringBuilder(); int most = 0; for (int v = 1; v <= n; v++) { if (v > 1) sb.Append(' '); sb.Append(term[v]); most = Math.Max(most, term[v]); } sb.Append('\n').Append(most).Append('\n'); Console.Write(sb); }}
C++main.cpp · 50 lines
#include <algorithm>#include <iostream>#include <queue>#include <vector>// t학기부터 세어 그 과목이 열리는 가장 이른 학기(kind 0: 모든 학기, 1: 홀수 학기, 2: 짝수 학기)int firstOpen(int t, int kind) { if ((kind == 1 && t % 2 == 0) || (kind == 2 && t % 2 == 1)) return t + 1; return t;}int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, m; std::cin >> n >> m; std::vector<int> kind(n + 1); for (int v = 1; v <= n; v++) std::cin >> kind[v]; std::vector<std::vector<int>> after(n + 1); // after[a] = a를 들어야 들을 수 있는 과목들 std::vector<int> waiting(n + 1, 0); // 아직 듣지 않은 선수 과목의 수 for (int i = 0; i < m; i++) { int a, b; std::cin >> a >> b; after[a].push_back(b); waiting[b]++; } std::vector<int> earliest(n + 1, 1); // 선수 과목만 보면 들을 수 있는 가장 이른 학기 std::vector<int> term(n + 1, -1); // 끝까지 -1이면 고리 때문에 들을 수 없다 std::queue<int> q; for (int v = 1; v <= n; v++) { if (waiting[v] == 0) q.push(v); } while (!q.empty()) { int a = q.front(); q.pop(); term[a] = firstOpen(earliest[a], kind[a]); // 선수 과목을 다 들었으니 이제 학기가 정해진다 for (int b : after[a]) { earliest[b] = std::max(earliest[b], term[a] + 1); // 가장 늦은 선수 과목의 다음 학기 if (--waiting[b] == 0) q.push(b); } } int most = 0; for (int v = 1; v <= n; v++) { std::cout << (v > 1 ? " " : "") << term[v]; most = std::max(most, term[v]); } std::cout << "\n" << most << "\n";}
Cmain.c · 59 lines
#include <stdio.h>#include <stdlib.h>// t학기부터 세어 그 과목이 열리는 가장 이른 학기(kind 0: 모든 학기, 1: 홀수 학기, 2: 짝수 학기)int first_open(int t, int kind) { if ((kind == 1 && t % 2 == 0) || (kind == 2 && t % 2 == 1)) return t + 1; return t;}int main(void) { int n, m; if (scanf("%d %d", &n, &m) != 2) return 0; int *kind = malloc((n + 1) * sizeof(int)); for (int v = 1; v <= n; v++) scanf("%d", &kind[v]); // 이음 목록을 배열 셋으로: head[a]에서 시작해 next[e]로 따라가며 to[e]를 본다 int *head = malloc((n + 1) * sizeof(int)); int *next = malloc((m + 1) * sizeof(int)); int *to = malloc((m + 1) * sizeof(int)); int *waiting = calloc(n + 1, sizeof(int)); // 아직 듣지 않은 선수 과목의 수 int *earliest = malloc((n + 1) * sizeof(int)); // 선수 과목만 보면 들을 수 있는 가장 이른 학기 int *term = malloc((n + 1) * sizeof(int)); int *queue = malloc((n + 1) * sizeof(int)); for (int v = 0; v <= n; v++) { head[v] = -1; earliest[v] = 1; term[v] = -1; // 끝까지 -1이면 고리 때문에 들을 수 없다 } for (int e = 0; e < m; e++) { int a, b; scanf("%d %d", &a, &b); to[e] = b; next[e] = head[a]; head[a] = e; waiting[b]++; } int qh = 0, qt = 0; for (int v = 1; v <= n; v++) { if (waiting[v] == 0) queue[qt++] = v; } while (qh < qt) { int a = queue[qh++]; term[a] = first_open(earliest[a], kind[a]); // 선수 과목을 다 들었으니 이제 학기가 정해진다 for (int e = head[a]; e != -1; e = next[e]) { int b = to[e]; if (term[a] + 1 > earliest[b]) earliest[b] = term[a] + 1; // 가장 늦은 선수 과목의 다음 학기 if (--waiting[b] == 0) queue[qt++] = b; } } int most = 0; for (int v = 1; v <= n; v++) { printf(v > 1 ? " %d" : "%d", term[v]); if (term[v] > most) most = term[v]; } printf("\n%d\n", most); free(kind); free(head); free(next); free(to); free(waiting); free(earliest); free(term); free(queue); return 0;}
Craykonmain.cray · 64 lines
// t학기부터 세어 그 과목이 열리는 가장 이른 학기(종류 0: 모든 학기, 1: 홀수 학기, 2: 짝수 학기)열리는학기(t, 종류){ if (종류 == 1 && t % 2 == 0 || 종류 == 2 && t % 2 == 1) { return t + 1; } return t;}첫줄 = Console.ReadNumbers();n = 첫줄[0];m = 첫줄[1];// 목록은 10,000칸까지라 과목 번호에서 1을 빼 0번부터 둔다kind = Console.ReadNumbers();after = []; // after[a] = a를 들어야 들을 수 있는 과목들for (v = 0; v < n; v++){ after.Add([]);}waiting = NewList(n, 0); // 아직 듣지 않은 선수 과목의 수for (i = 0; i < m; i++){ 쌍 = Console.ReadNumbers(); after[쌍[0] - 1].Add(쌍[1] - 1); waiting[쌍[1] - 1] += 1;}earliest = NewList(n, 1); // 선수 과목만 보면 들을 수 있는 가장 이른 학기term = NewList(n, -1); // 끝까지 -1이면 고리 때문에 들을 수 없다queue = [];for (v = 0; v < n; v++){ if (waiting[v] == 0) { queue.Add(v); }}// 앞에서 꺼내는 대신 머리 번호 head를 옮긴다head = 0;while (head < queue.Count){ a = queue[head]; head++; term[a] = 열리는학기(earliest[a], kind[a]); // 선수 과목을 다 들었으니 이제 학기가 정해진다 foreach (b in after[a]) { earliest[b] = Mathf.Max(earliest[b], term[a] + 1); // 가장 늦은 선수 과목의 다음 학기 waiting[b] -= 1; if (waiting[b] == 0) { queue.Add(b); } }}most = 0;foreach (t in term){ most = Mathf.Max(most, t);}Console.WriteLine(term);Console.WriteLine(most);