読者です 読者をやめる 読者になる 読者になる

mayoko’s diary

プロコンとかいろいろ。

AOJ 2022: Princess, a Cryptanalyst

解法

N! 通りの並び方を試します。で, apple, length の "le" のように前の文字の後半, 後ろの文字の前半で一致しているところがあったら applength のようにつなげて考えればいけます。…と言いたいところなんですがこれでは WA です(これで引っかかりました…)。

apple, pp という文字列があったとすると, apple の中には pp という文字列が含まれているので, applepp とせず, apple と書けば終わりです。こういうのに気を付けて,

same[i][j] = (i 番目の文字の後に j 番目の文字は何文字書かないといけないか。また, そのあと後半に続いている文字は i 番目のものか j 番目のものか) というような配列を作ります。
例えば apple, length の場合は, apple の後に length は後半の 4 文字だけ書けば良いので 「i 番目の文字の後に j 番目の文字は何文字書かないといけないか」というのは 4 です。で, 後半に続いているのは length なので 2 つ目の要素は j です。
一方で apple, pp の場合は, 「i 番目の文字の後に j 番目の文字は何文字書かないといけないか」というのは 0 です。で, pp は apple の途中にあるので, 「そのあと後半に続いている文字は i 番目のものか j 番目のものか)」というのは i です。

よく考えると 1 つ目の要素が j 番目の文字の長さと一致していたら 2 番目の要素は i, とすればよかっただけでした。マァイイヤ

ICPC は基本的にサンプルが丁寧なイメージですがこれはちょっと厳しかったですね。

pii same[15][15];
char ans[200], tmp[200];
int asize = 0;

// s < t かどうか
bool comp(const char*s, int ssize, const char* t, int tsize) {
	if (ssize < tsize) return true;
	if (ssize > tsize) return false;
	for (int i = 0; i < ssize; i++) {
		if (s[i] < t[i]) return true;
		if (s[i] > t[i]) return false;
	}
	return true;
}

int main() {
    int N;
    while (cin >> N) {
    	if (N==0) break;
    	vector<string> ss(N);
    	for (int i = 0; i < N; i++)
    		cin >> ss[i];
    	for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {
    		int sz = min(ss[i].size(), ss[j].size());
    		int maxi = 0;
    		for (int k = 1; k <= sz; k++) {
    			if (ss[i].substr(ss[i].size()-k, k) == ss[j].substr(0, k)) maxi = k;
    		}
    		same[i][j] = pii(maxi, j);
    		for (int k = 0; k < ss[i].size(); k++) {
    			if (ss[i].substr(k, ss[j].size()) == ss[j]) same[i][j] = pii(ss[j].size(), i);
    		}
    	}
    	vector<int> perm(N);
    	for (int i = 0; i < N; i++) 
    		perm[i] = i;
    	bool first = true;
    	do {
    		int sz = 0;
    		for (int i = 0; i < ss[perm[0]].size(); i++) 
    			tmp[i] = ss[perm[0]][i];
    		sz = ss[perm[0]].size();
    		int now = perm[0];
    		for (int i = 0; i < N-1; i++) {
    			int next = perm[i+1];
    			pii p = same[now][next];
    			int len = p.first;
    			for (int j = len; j < ss[next].size(); j++)
    				tmp[sz++] = ss[next][j];
    			now = p.second;
    		}
    		if (first || !comp(ans, asize, tmp, sz)) {
    			asize = sz;
    			for (int i = 0; i < sz; i++)
    				ans[i] = tmp[i];
    		}
    		first = false;
    	} while (next_permutation(perm.begin(), perm.end()));
    	for (int i = 0; i < asize; i++)
    		printf("%c", ans[i]);
    	printf("\n");
    }
    return 0;
}