#include #include #include #include using namespace std; typedef vector VI; typedef vector VVI; typedef vector VVVI; int ComputeMinLength(const string &s, const vector &T) { const int L = int(s.length()-1); // best[i][j] = smallest possible reduced length for s[i+1...j] // reachable[k][j][l] = 1[can match s[i+1...j] with t[k][0...l]] // removable[j] = list of all i's for which best[i][j] = 0 and i < j VVI best(L+1, VI(L+1, L)); VVVI reachable(T.size(), VVI(L+1)); VVI removable(L+1); for (int k = 0; k < T.size(); k++) for (int j = 0; j <= L; j++) reachable[k][j].resize(T[k].length()); // consider substrings of increasing length for (int i = L; i >= 0; i--) { for (int j = i; j <= L; j++) { // for each substring, consider subproblems best[i][j] = min(best[i][j], j-i); // nothing to remove if (j-i >= 1) { best[i][j] = min(best[i][j], best[i+1][j]+1); // add character on left best[i][j] = min(best[i][j], best[i][j-1]+1); // add character on right for (int k = i+1; k <= j-1; k++) best[i][j] = min(best[i][j], best[i][k] + best[k][j]); // concatenation } // removable substrings for (size_t k = 0; k < T.size(); k++) { for (int l = 0; l < T[k].length(); l++) { reachable[k][j][l] = 0; if (j == i && l == 0) { reachable[k][j][l] = 1; } else if (j > i) { if (l > 0 && s[j] == T[k][l]) reachable[k][j][l] = reachable[k][j][l] || reachable[k][j-1][l-1]; for (VI::iterator iter = removable[j].begin(); !reachable[k][j][l] && iter != removable[j].end(); ++iter) { assert(*iter >= i); reachable[k][j][l] = reachable[k][*iter][l]; } } } if (reachable[k][j][T[k].length()-1]) best[i][j] = 0; } if (best[i][j] == 0 && i < j){ removable[j].push_back(i); } } } return best[0][L]; } int main() { while (1) { int n; cin >> n; if (n == 0) break; string s; cin >> s; s = "@" + s; vector T(n); for (int i = 0; i < n; i++){ cin >> T[i]; T[i] = "@" + T[i]; } cout << ComputeMinLength(s, T) << endl; } return 0; }