cppAcademy
FROM LEARNING TO COMPETING

Intermediate.
Put your skills to the test.

Bulgarian Informatics Group D · 2007–2026

270 independently explained problems: 54 Municipal, 54 Regional, 105 National Olympiad and 57 Autumn Tournament tasks. Start with the easier tasks and work upwards. Difficulty labels are learning estimates, not official ratings; Group D also includes challenging national-level problems. The six 2017 National tasks shared by Groups C and D use their existing permanent URLs. Years follow Arena’s competition-season labels. Source clarifications and special grader requirements are noted on affected tasks.
GROUP D2007 · MediumSimulation

Word Chain

Autumn Tournament (2007)

Submission name: words.cpp

Problem summary

Build the longest chain of supplied words such that each next word begins with the last letter of the previous word. A word can be used once. The statement guarantees that a matching next word, when one exists, is unique. Break equal-length ties by the alphabetically smallest first word. Print 0 if no pair of words can be linked.

Source clarification. The source does not explicitly define a length-one chain or the alphabet beyond its examples. We follow its “no matching words → 0” instruction and ordinary lexicographic ordering of the supplied Latin words. The unique-successor promise is essential.

Input

N followed by N words.

Output

The chain length, followed by its words on separate lines; or 0 if no chain of at least two words exists.

Constraints

1 ≤ N ≤ 26; each word has at most 10 letters.

Worked example

Original statement sample.

Input

5
bear
new
door
sky
word

Output

3
new
word
door

Solution analysis

  1. Try every word as the first word. Because the next word is unique, there is no branching choice after that starting point. Search the input for an unused word beginning with the current word’s last letter.
  2. Keep a used array for this particular attempt. Stop when no unused successor exists. This also stops a cycle: returning to a previously used word is forbidden. Compare the resulting chain with the best by length and then by its first word.
  3. For the sample, starting from new produces new → word → door. Starting from word gives only word → door, and bear and sky cannot extend the best chain. The chosen length is therefore 3.

Why it works

Every valid chain has a supplied first word. For a fixed first word, the unique-successor promise forces every subsequent usable word; stopping at a missing or already used successor is necessary. Trying all first words therefore includes a longest chain, and the comparison applies the required tie-break.

Complexity: O(N³ + NL) time with direct successor scans, where L ≤ 10 is the maximum word length; O(NL + N) space. There are N starts, at most N steps per start, and N candidates per step.

Watch out. Reset the used array for every starting word. Do not reuse words around a cycle. The source says to output 0 when no words satisfy the linking condition; this implementation treats a single isolated word as no chain.

Commented C++17 solution

An independently written complete program with standard headers.

#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){
    int n;
    cin>>n;
    vector<string>words(n);
    for(string&word:words){
        cin>>word;
    }
    vector<int>best;
    for(int start=0;start<n;start++){
        vector<bool>used(n,false);
        vector<int>chain;
        int current=start;
        while(current!=-1){
            chain.push_back(current);
            used[current]=true;
            int next=-1;
            for(int candidate=0;candidate<n;candidate++){
                if(!used[candidate]&&words[candidate].front()==words[current].back()){
                    next=candidate;
                    break;
                }
            }
            current=next;
        }
        // With unique successors, only the first word breaks equal-length ties.
        if(chain.size()>best.size()||
            (chain.size()==best.size()&&words[start]<words[best.front()])){
            best=chain;
        }
    }
    if(best.size()<2){
        cout<<0<<'\n';
        return 0;
    }
    cout<<best.size()<<'\n';
    for(int index:best){
        cout<<words[index]<<'\n';
    }
}

Source: Arena Olimpiici ↗