All IOI entries
Competitive Programming

IOI 1996 - Network of Schools

Problem Statement A network of n schools is connected by one-way links. Software distributed to a school propagates transitively along outgoing links. Task A: Find the minimum number of schools that must receive the s...

Source sync Apr 19, 2026
Track IOI
Year 1996
Files TeX and C++
Folder competitive_programming/ioi/1996/network_of_schools
IOI1996TeXC++

Source-first archive entry

This page is built from the copied files in competitive_programming/ioi/1996/network_of_schools. Edit competitive_programming/ioi/1996/network_of_schools/solution.tex to update the written solution and competitive_programming/ioi/1996/network_of_schools/solution.cpp to update the implementation.

The website does not replace those files with hand-maintained HTML. It reads the copied source tree during the build and exposes the exact files below.

Problem Statement

Rendered from the "Problem Statement" section inside solution.tex because this entry has no separate statement file.

A network of $n$ schools is connected by one-way links. Software distributed to a school propagates transitively along outgoing links.

  • Task A: Find the minimum number of schools that must receive the software initially so that all schools eventually receive it.

  • Task B: Find the minimum number of one-way links to add so that distributing software to any single school causes all schools to receive it (i.e., make the graph strongly connected).

  • Constraints: $2 \le n \le 100$.

Editorial

Rendered from the copied solution.tex file. The original TeX source remains available below.

Solution Approach

Step 1: Strongly Connected Components

Use Kosaraju's algorithm (or Tarjan's) to compute the SCCs. Condense the graph into a DAG where each node represents an SCC.

Step 2: Analyze the Condensed DAG

Let $S$ denote the number of SCCs.

  • Task A: The answer is the number of source nodes (in-degree 0) in the condensed DAG. These SCCs cannot be reached from any other SCC, so each must receive software directly: \[ \text{Answer A} = |\{v : \deg^-(v) = 0\}|. \]

  • Task B: To make the condensed DAG strongly connected, we must eliminate all sources and sinks. The minimum number of edges required is: \[ \text{Answer B} = \max(\text{sources}, \text{sinks}), \] where sources and sinks refer to nodes with in-degree 0 and out-degree 0 in the condensed DAG, respectively.

Proof (Justification for Task B).

Each added edge can eliminate at most one source and one sink. Therefore $\max(\text{sources}, \text{sinks})$ is a lower bound. A matching construction (pairing sources with sinks and connecting them cyclically) achieves this bound.

Special case: If $S = 1$ (the graph is already strongly connected), then Answer A = 1 and Answer B = 0.

C++ Solution

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 105;
int n;
vector<int> adj[MAXN], radj[MAXN];
int comp[MAXN];
bool visited[MAXN];
int order_arr[MAXN], order_cnt;

// Kosaraju's Algorithm -- Pass 1: forward DFS, record finish order
void dfs1(int u) {
    visited[u] = true;
    for (int v : adj[u])
        if (!visited[v]) dfs1(v);
    order_arr[order_cnt++] = u;
}

// Kosaraju's Algorithm -- Pass 2: reverse DFS, assign component IDs
void dfs2(int u, int c) {
    comp[u] = c;
    for (int v : radj[u])
        if (comp[v] == -1) dfs2(v, c);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int v;
        while (scanf("%d", &v) == 1 && v != 0) {
            adj[i].push_back(v);
            radj[v].push_back(i);
        }
    }

    // Pass 1
    memset(visited, false, sizeof(visited));
    order_cnt = 0;
    for (int i = 1; i <= n; i++)
        if (!visited[i]) dfs1(i);

    // Pass 2
    memset(comp, -1, sizeof(comp));
    int numSCC = 0;
    for (int i = order_cnt - 1; i >= 0; i--)
        if (comp[order_arr[i]] == -1)
            dfs2(order_arr[i], numSCC++);

    if (numSCC == 1) {
        printf("1\n0\n");
        return 0;
    }

    // Build condensed DAG: determine which SCCs have incoming/outgoing edges
    // We only need to know whether in-degree and out-degree are zero,
    // so duplicate edges between the same pair of SCCs do not affect the result.
    bool hasIn[MAXN] = {}, hasOut[MAXN] = {};
    for (int u = 1; u <= n; u++)
        for (int v : adj[u])
            if (comp[u] != comp[v]) {
                hasIn[comp[v]] = true;
                hasOut[comp[u]] = true;
            }

    int sources = 0, sinks = 0;
    for (int i = 0; i < numSCC; i++) {
        if (!hasIn[i]) sources++;
        if (!hasOut[i]) sinks++;
    }

    printf("%d\n%d\n", sources, max(sources, sinks));
    return 0;
}

Complexity Analysis

  • Time complexity: $O(n + m)$ where $m$ is the number of edges. Kosaraju's algorithm runs two DFS passes, each $O(n + m)$. Computing sources and sinks in the condensed DAG is $O(n + m)$.

  • Space complexity: $O(n + m)$ for the adjacency lists and reverse graph.

Code

Exact copied C++ implementation from solution.cpp.

C++ competitive_programming/ioi/1996/network_of_schools/solution.cpp

Exact copied implementation source.

Raw file
// IOI 1996 - Network of Schools
// Kosaraju's SCC + condensed DAG analysis
// Task A: count sources (in-degree 0) in condensed DAG
// Task B: max(sources, sinks) to make graph strongly connected
// Time: O(n + m), Space: O(n + m)
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 105;
int n;
vector<int> adj[MAXN], radj[MAXN];
int comp[MAXN];
bool visited[MAXN];
int order_arr[MAXN], order_cnt;

void dfs1(int u) {
    visited[u] = true;
    for (int v : adj[u])
        if (!visited[v]) dfs1(v);
    order_arr[order_cnt++] = u;
}

void dfs2(int u, int c) {
    comp[u] = c;
    for (int v : radj[u])
        if (comp[v] == -1) dfs2(v, c);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int v;
        while (scanf("%d", &v) == 1 && v != 0) {
            adj[i].push_back(v);
            radj[v].push_back(i);
        }
    }

    // Kosaraju's SCC
    memset(visited, false, sizeof(visited));
    order_cnt = 0;
    for (int i = 1; i <= n; i++)
        if (!visited[i]) dfs1(i);

    memset(comp, -1, sizeof(comp));
    int numSCC = 0;
    for (int i = order_cnt - 1; i >= 0; i--)
        if (comp[order_arr[i]] == -1)
            dfs2(order_arr[i], numSCC++);

    if (numSCC == 1) {
        printf("1\n0\n");
        return 0;
    }

    // Build condensed DAG, track which SCC pairs have edges
    set<pair<int,int>> condEdges;
    bool hasIn[MAXN] = {}, hasOut[MAXN] = {};
    for (int u = 1; u <= n; u++)
        for (int v : adj[u])
            if (comp[u] != comp[v]) {
                auto e = make_pair(comp[u], comp[v]);
                if (condEdges.insert(e).second) {
                    hasIn[comp[v]] = true;
                    hasOut[comp[u]] = true;
                }
            }

    int sources = 0, sinks = 0;
    for (int i = 0; i < numSCC; i++) {
        if (!hasIn[i]) sources++;
        if (!hasOut[i]) sinks++;
    }

    printf("%d\n%d\n", sources, max(sources, sinks));
    return 0;
}

Source Files

Exact copied source-of-truth files. Edit solution.tex for the write-up and solution.cpp for the implementation.

TeX write-up competitive_programming/ioi/1996/network_of_schools/solution.tex

Exact copied write-up source.

Raw file
\documentclass[11pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath,amssymb,amsthm}
\usepackage{geometry}
\geometry{margin=2.5cm}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{hyperref}

\lstset{
  language=C++,
  basicstyle=\ttfamily\small,
  keywordstyle=\color{blue}\bfseries,
  commentstyle=\color{green!60!black},
  stringstyle=\color{red!70!black},
  numbers=left,
  numberstyle=\tiny\color{gray},
  numbersep=8pt,
  frame=single,
  breaklines=true,
  tabsize=4,
  showstringspaces=false
}

\title{IOI 1996 -- Network of Schools}
\author{Solution}
\date{}

\begin{document}
\maketitle

\section{Problem Statement}

A network of $n$ schools is connected by one-way links. Software distributed to a school
propagates transitively along outgoing links.

\begin{itemize}
  \item \textbf{Task A:} Find the minimum number of schools that must receive the software
    initially so that all schools eventually receive it.
  \item \textbf{Task B:} Find the minimum number of one-way links to add so that
    distributing software to \emph{any single} school causes all schools to receive it
    (i.e., make the graph strongly connected).
\end{itemize}

\noindent\textbf{Constraints:} $2 \le n \le 100$.

\section{Solution Approach}

\subsection{Step 1: Strongly Connected Components}

Use Kosaraju's algorithm (or Tarjan's) to compute the SCCs. Condense the graph into a
DAG where each node represents an SCC.

\subsection{Step 2: Analyze the Condensed DAG}

Let $S$ denote the number of SCCs.

\begin{itemize}
  \item \textbf{Task A:} The answer is the number of \emph{source nodes}
    (in-degree 0) in the condensed DAG. These SCCs cannot be reached from any
    other SCC, so each must receive software directly:
    \[
      \text{Answer A} = |\{v : \deg^-(v) = 0\}|.
    \]

  \item \textbf{Task B:} To make the condensed DAG strongly connected, we must
    eliminate all sources and sinks. The minimum number of edges required is:
    \[
      \text{Answer B} = \max(\text{sources}, \text{sinks}),
    \]
    where sources and sinks refer to nodes with in-degree 0 and out-degree 0
    in the condensed DAG, respectively.
\end{itemize}

\begin{proof}[Justification for Task B]
Each added edge can eliminate at most one source and one sink. Therefore
$\max(\text{sources}, \text{sinks})$ is a lower bound. A matching construction
(pairing sources with sinks and connecting them cyclically) achieves this bound.
\end{proof}

\noindent\textbf{Special case:} If $S = 1$ (the graph is already strongly connected),
then Answer A = 1 and Answer B = 0.

\section{C++ Solution}

\begin{lstlisting}
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 105;
int n;
vector<int> adj[MAXN], radj[MAXN];
int comp[MAXN];
bool visited[MAXN];
int order_arr[MAXN], order_cnt;

// Kosaraju's Algorithm -- Pass 1: forward DFS, record finish order
void dfs1(int u) {
    visited[u] = true;
    for (int v : adj[u])
        if (!visited[v]) dfs1(v);
    order_arr[order_cnt++] = u;
}

// Kosaraju's Algorithm -- Pass 2: reverse DFS, assign component IDs
void dfs2(int u, int c) {
    comp[u] = c;
    for (int v : radj[u])
        if (comp[v] == -1) dfs2(v, c);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int v;
        while (scanf("%d", &v) == 1 && v != 0) {
            adj[i].push_back(v);
            radj[v].push_back(i);
        }
    }

    // Pass 1
    memset(visited, false, sizeof(visited));
    order_cnt = 0;
    for (int i = 1; i <= n; i++)
        if (!visited[i]) dfs1(i);

    // Pass 2
    memset(comp, -1, sizeof(comp));
    int numSCC = 0;
    for (int i = order_cnt - 1; i >= 0; i--)
        if (comp[order_arr[i]] == -1)
            dfs2(order_arr[i], numSCC++);

    if (numSCC == 1) {
        printf("1\n0\n");
        return 0;
    }

    // Build condensed DAG: determine which SCCs have incoming/outgoing edges
    // We only need to know whether in-degree and out-degree are zero,
    // so duplicate edges between the same pair of SCCs do not affect the result.
    bool hasIn[MAXN] = {}, hasOut[MAXN] = {};
    for (int u = 1; u <= n; u++)
        for (int v : adj[u])
            if (comp[u] != comp[v]) {
                hasIn[comp[v]] = true;
                hasOut[comp[u]] = true;
            }

    int sources = 0, sinks = 0;
    for (int i = 0; i < numSCC; i++) {
        if (!hasIn[i]) sources++;
        if (!hasOut[i]) sinks++;
    }

    printf("%d\n%d\n", sources, max(sources, sinks));
    return 0;
}
\end{lstlisting}

\section{Complexity Analysis}

\begin{itemize}
  \item \textbf{Time complexity:} $O(n + m)$ where $m$ is the number of edges.
        Kosaraju's algorithm runs two DFS passes, each $O(n + m)$. Computing
        sources and sinks in the condensed DAG is $O(n + m)$.
  \item \textbf{Space complexity:} $O(n + m)$ for the adjacency lists and reverse graph.
\end{itemize}

\end{document}