Saruman's Secret Message
Difficulty: Hard

Saruman occasionally sends top-secret messages to his orc commanders using a horde of bats. Because each bat can only carry a limited amount of weight, Saruman breaks up each message into many smaller fragments, with each bat carrying a single message fragment. To reduce the possibility of detection in case one or more bats are captured, Saruman sends many copies of each message, with copies fragmented in different ways.

To decode the message, the recipient must combine the different message fragments, using the overlapping regions as hints. For instance, the fragment "abcde" can be combined with the fragment "cdefgh" to form "abcdefgh". Though there may be many ways to combine the message fragments, the shortest combination is generally taken to be the most correct result. For instance, given the fragments "abaca" and "acada", two possible combinations are "abacada" and "abacacada". To simplify decoding the message, Saruman always begins each message with the marker "ZZZ". 

If parts of the message are lost, it is possible that the message fragments cannot be combined into a single contiguous message. You may assume this did not happen with your message. Even without losing any fragments, assembling a single message can be difficult (or impossible) in the general case. For simplicity you may assume that the shortest combination (with maximum overlap) yields the correct message, and that there is only one such combination (i.e., at each step only one message fragment will have the maximum overlap).   

A few days ago Saruman sent you and your fellow orcs to track down and "take care" of some troublesome hobbits near your tower. You can tell you are getting close and are looking forward to having a little "snack" upon completion of your task, when bats begin arriving with many message fragments. You sigh and begin the laborious task of putting the coded message together, wondering in the back of your mind whether wizards will ever discover some spell to magically assemble such messages.

**Input Format:**
The number of message fragments (as an integer), followed by each message fragment (as a string) on a separate line. You may assume that all message fragments are exactly 12 letters, and that you will receive at most 100 message fragments. If there are multiple ways to overlap fragments, choose the combination which yields the shortest result (i.e., maximum overlap). You may assume the fragment with the maximum overlap is unique.  
The beginning of each message always contains the marker "ZZZ".

**Output Format:**
The text of the complete message, without the beginning "ZZZ" marker.

**Sample Input:**  
17  
em.down!.Do.  
l.they.are.f  
ZZZHunt.them  
o.not.stop.u  
.until.they.  
t.them.down!  
Hunt.them.do  
n!.Do.not.st  
y.are.found.  
p.until.they  
.them.down!.  
they.are.fou  
.not.stop.un  
.Do.not.stop  
down!.Do.not  
t.stop.until  
.stop.until.  


**Sample Output:**  
Hunt.them.down!.Do.not.stop.until.they.are.found.




Input Format:

Output Format:

Sample Input:

Sample Output:

Python 3 starter code:


Reference solution (C++):
    #include <stdlib.h>
    #include <iostream.h>
    #include <assert.h>

    // Uncomment the following lines if using APCS classes
    // #include "apvector.h"
    // #include "apmatrix.h"
    // #include "apstack.h"
    // #include "apqueue.h"

    #include "apstring.cpp"

    //-----------------------------------------------------------------------
    //  main
    //-----------------------------------------------------------------------

    int main()
    {
	const int FRAGSIZE = 12;
	const int MAXFRAG = 100;
	apstring frag[MAXFRAG], result, str, marker, head, tail;
	int numFrag, i, k, maxOverlap, overlapIdx, overlapIdx2, slen;
	bool found;

	// read in all fragments

	cin >> numFrag;
	for (i = 0; i < numFrag; i++) {
		cin >> frag[i];
		if (frag[i].length() != FRAGSIZE) {
			cout << "ERROR, illegal fragment size " << frag[i] << endl;
		}
	}

	// find beginning marker, use as current result
	
	marker = apstring("ZZZ");
	slen = marker.length();
	found = false;

	for (i = 0; i < numFrag; i++) {
		if (marker == frag[i].substr(0, slen)) {
			result = apstring(frag[i]);
			frag[i] = frag[--numFrag];
			found = true;
			break;
		}
	}

	if (!found) {
		cout << "ERROR, no fragment with initial marker " << marker << endl;
	}

	// assemble fragments

	while (numFrag > 0) {

		// find fragment with greatest overlap to end of current result

		maxOverlap = 0;
		overlapIdx2 = -1;

		for (i = 0; i < numFrag; i++) {

			// check if entire fragment is subsumed in string
			while (result.find(frag[i]) != npos) {
				frag[i] = frag[--numFrag];
			}

			if (i == numFrag)  // no more fragments
				break;

			for (k = maxOverlap+1; k < FRAGSIZE; k++) {
				head = frag[i].substr(0,k);
				tail = result.substr(result.length() - k, k);
				if (head == tail) {
					if (k > maxOverlap) {
						maxOverlap = k;
						overlapIdx = i;
					}
					else if (k == maxOverlap) {
						overlapIdx2 = i;
					}
				}
			}
		}

		// append fragment with greatest overlap to end of current result

		if (maxOverlap > 0) {
			// cout << "Merging " << maxOverlap << " " << result << " " << frag[overlapIdx];
			result += frag[overlapIdx].substr(maxOverlap, FRAGSIZE-maxOverlap);
			frag[overlapIdx] = frag[--numFrag];

			if (overlapIdx2 >= 0) {
				cout << "Error, found multiple fragments with max overlap: " << endl;
				cout << frag[overlapIdx] << " && " << frag[overlapIdx2] << endl;
			}
		}
		else {
			cout << "Error, unable to assemble complete message " << endl;
			cout << "Remaining fragments: \n";
			for (k = 0; k < numFrag; k++) {
				cout << frag[k] << endl;
			}
			break;
		}
	}

	cout << result.substr(slen, result.length()-slen) << endl;

	return 0;
    }