Source: USAMO-2022-P6
Category: Graph Theory

Problem: There are $2022$ users on a social network called Mathbook, and some of them are Mathbook-friends. (On Mathbook, friendship is always mutual and permanent.)\nStarting now, Mathbook will only allow a new friendship to be formed between two users if they have at least two friends in common. What is the minimum number\nof friendships that must already exist so that every user could eventually become friends with every other user?

Answer: With $2022$ replaced by $n$, the answer is $\\lceil 3/2n \\rceil - 2$.

Reference solution:
With $2022$ replaced by $n$, the answer is $\left\lceil \frac{3}{2} n \right\rceil - 2$.

In standard graph theory terms: starting from a graph $G$ on $n$ vertices, we are allowed to take any $C_4$ in the graph and complete it to a $K_4$. The problem asks for the minimum number of edges needed so that this operation lets us transform $G$ to $K_n$. 

For even $n$, start with an edge $ab$, and then create $n/2-1$ copies of $C_4$ that use $ab$ as an edge. This can be completed into $K_n$ by first completing the $n/2-1$ copies of $C_4$ into $K_4$. Then, since any two vertices in different copies of $K_4$ share $a$ and $b$ as common friends, we can connect all remaining pairs of vertices, finishing up the $K_n$. The construction for odd $n$ is the same except with one extra vertex $c$ which is connected to both $a$ and $b$. 

Notice that additional operations or connections can never hurt. So we will describe a *specific* algorithm that performs operations on the graph until no more operations are possible. This means that if this algorithm terminates with anything other than $G = K_n$, the graph was never completable to $K_n$ to begin with. 

The algorithm uses the following data: it keeps a list $\mathcal{C}$ of cliques of $G$, and a labeling $\mathcal{L} \colon E(G) \to \mathcal{C}$ which assigns to every edge one of the cliques that contains it. Initially, $\mathcal{C}$ consists of one $K_2$ for every edge of $G$, and each edge is labeled in the obvious way. 

At each step, the algorithm arbitrarily takes any $C_4 = abcd$ whose four edges $ab$, $bc$, $cd$, $da$ do not all have the same label. Consider these labels that appear (at least two, and up to four), and let $V$ be the union of all vertices in any of these $2$ to $4$ cliques. Do the following graph operations: connect $ac$ and $bd$, then connect every vertex in $V \setminus \{a,b,c,d\}$ to each of $\{a,b,c,d\}$. Finally, complete this to a clique on $V$. 

Update $\mathcal{C}$ by merging these $2$ to $4$ cliques into a single clique $K_V$. Update $\mathcal{L}$ by replacing every edge that was labeled with one of these cliques with the label $K_V$. Also, update every *newly* created edge to have label $K_V$. However, if there were existing edges not labeled with one of the merged cliques, then we do *not* update these. 

Stop once every $C_4$ has only one label appearing among its edges. When this occurs, no operations are possible at all on the graph. As we remarked, if the graph is going to be completable to $K_n$ at all, then this algorithm must terminate with $\mathcal{C} = \{K_n\}$. We will use this to prove our bound. 

We proceed by induction in the following way. For a clique $K$, let $\theta(K)$ denote the number of edges of the *original* graph $G$ which are labeled by $K$ (this does *not* include new edges added by the algorithm); hence the problem amounts to estimating how small $\theta(K_n)$ can be. 

At any point in the operation, if $K$ is a clique in the cover $\mathcal{C}$, then 
$$ \theta(K) \ge \frac{3 |K|}{2} - 2 $$
where $|K|$ is the number of vertices in $K$. We prove this by induction on the time step of the algorithm. The base case is clear, because initially $K$ is just a single edge of $G$, so $\theta(K) = 1$ and $|K| = 2$, which satisfies $1 \ge \frac{3(2)}{2} - 2 = 1$. The inductive step proceeds by casework based on how the merge occurred.

Grading guidelines:
(Partial) 1. Gave (and correctly justified) a construction achieving at most \(\lceil \tfrac32 n\rceil-2\) initial friendships, e.g. for even \(n\) an edge \(ab\) plus \(\frac n2-1\) disjoint 4-cycles sharing \(ab\), and explained how the allowed rule can then generate all remaining edges. 2. Reformulated the process in graph terms (new edge \(uv\) can be added once \(u,v\) have at least two common neighbors; equivalently one may complete a \(C_4\) to a \(K_4\)), and made a correct nontrivial structural observation about how the closure operation behaves (e.g. completing one \(K_4\) creates two common neighbors \(a,b\) that then force edges between vertices from different blocks). 3. Proved a meaningful lower-bound lemma, e.g. established a bound of the form \(e(G)\ge c n - O(1)\) (with some explicit \(c>1\)) necessary for eventual completion to \(K_n\), or proved the key invariant for cliques \(K\) that \(\theta(K)\ge \frac{3|K|}{2}-2\) in the base case and at least one nontrivial merge case. (Almost) 1. Presented the full lower-bound strategy via the clique-merging/labeling algorithm (or an equivalent invariant argument), but left a localized gap in the inductive step when multiple cliques merge (e.g. did not fully justify why the merge step is legal under the “two common friends” rule, or omitted one subcase of how \(\theta\) changes). 2. Proved the sharp lower bound \(e(G)\ge \lceil\tfrac32 n\rceil-2\) and gave the sharp construction, but did not handle one parity/boundary case (typically the odd \(n\) adjustment with the extra vertex adjacent to \(a,b\)), or made a small counting slip that affects only that case. 3. Solution is almost complete, but made minor mistakes which are not negligible.

Construction task:
For the specific case $n=202$ (where the users are represented by integers from 1 to 202), provide an explicit construction of the initial friendships that achieves the minimum possible number of friendships.

Construction requirements:
- Output a single Python expression that evaluates to a list of 2-tuples of integers.
- Each tuple `(u, v)` represents a friendship between user `u` and user `v`.
- The users must be integers from 1 to 202.
- The number of friendships in your list must be exactly the minimum required for $n=202$.
- The provided initial friendships must allow every user to eventually become friends with every other user under the rule that a new friendship can be formed if two users have at least two friends in common.
- The output must be a single, valid Python expression (e.g., using list comprehensions) that can be evaluated directly by `eval()`. Do not include comments, assignments, or any other code.
- Put ONLY the Python expression inside the construction block.

Reference construction:
[(1, 2)] + [edge for i in range(2, 102) for edge in ((2, 2*i - 1), (2*i - 1, 2*i), (2*i, 1))]

Verifier code:
import sys
import collections

def verify():
    payload = sys.stdin.read().strip()
    if not payload:
        print("Empty input.")
        return

    try:
        # Evaluate the payload. The instruction explicitly allows Python expressions
        # like list comprehensions, so eval() is used.
        edges_raw = eval(payload)
    except Exception as e:
        print(f"Failed to evaluate input: {e}")
        return

    try:
        edges_list = list(edges_raw)
    except Exception as e:
        print(f"Output is not an iterable: {e}")
        return

    normalized_edges = set()
    for edge in edges_list:
        if not isinstance(edge, tuple) or len(edge) != 2:
            print(f"Invalid edge format: {edge}. Must be a 2-tuple.")
            return
        u, v = edge
        if not (isinstance(u, int) and isinstance(v, int)):
            print(f"Edge vertices must be integers: {edge}")
            return
        if not (1 <= u <= 202 and 1 <= v <= 202):
            print(f"Vertices must be between 1 and 202: {edge}")
            return
        if u == v:
            print(f"Self-loops are not allowed: {edge}")
            return
        # Normalize edge to be undirected
        normalized_edges.add(tuple(sorted((u, v))))

    if len(normalized_edges) != 301:
        print(f"Expected exactly 301 unique friendships, got {len(normalized_edges)}.")
        return

    # Simulate friendship formation
    adj = {i: set() for i in range(1, 203)}
    for u, v in normalized_edges:
        adj[u].add(v)
        adj[v].add(u)

    # Precompute common friends for all pairs
    common_friends = {i: {j: 0 for j in range(1, 203)} for i in range(1, 203)}
    for i in range(1, 203):
        for j in range(i + 1, 203):
            c = len(adj[i].intersection(adj[j]))
            common_friends[i][j] = c
            common_friends[j][i] = c

    queue = collections.deque()
    in_queue_or_adj = {i: set(adj[i]) for i in range(1, 203)}

    # Enqueue all pairs that initially have >= 2 common friends
    for i in range(1, 203):
        for j in range(i + 1, 203):
            if j not in in_queue_or_adj[i] and common_friends[i][j] >= 2:
                queue.append((i, j))
                in_queue_or_adj[i].add(j)
                in_queue_or_adj[j].add(i)

    # Process queue to propagate new friendships
    while queue:
        u, v = queue.popleft()
        
        # For every existing neighbor w of u, u acts as a new common friend for w and v
        for w in adj[u]:
            common_friends[w][v] += 1
            common_friends[v][w] += 1
            if v not in in_queue_or_adj[w] and common_friends[w][v] >= 2:
                queue.append((w, v))
                in_queue_or_adj[w].add(v)
                in_queue_or_adj[v].add(w)
                
        # For every existing neighbor w of v, v acts as a new common friend for w and u
        for w in adj[v]:
            common_friends[w][u] += 1
            common_friends[u][w] += 1
            if u not in in_queue_or_adj[w] and common_friends[w][u] >= 2:
                queue.append((w, u))
                in_queue_or_adj[w].add(u)
                in_queue_or_adj[u].add(w)
                
        # Add the validated friendship to the active adjacency list
        adj[u].add(v)
        adj[v].add(u)

    # Verify if the graph has become complete
    total_edges = sum(len(neighbors) for neighbors in adj.values()) // 2
    expected_edges = 202 * 201 // 2
    if total_edges != expected_edges:
        print(f"Graph does not become complete. Final edge count: {total_edges} instead of {expected_edges}.")
        return

    print("True")

if __name__ == "__main__":
    verify()