//Memory 156K Time 47MS
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
string *geneStr;
bool *visit;
int n, minLength, **addLength;
void updateLength(){
//枚举所有的基因片段
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++){
if (i == j)
continue;
//计算出两个字符串的最小长度
int minLen = geneStr[i].length() < geneStr[j].length() ? geneStr[i].length(): geneStr[j].length();
//最坏情况,将j字符串全部拼接在i字符串后面
for (int r = minLen; r >= 0; r--){
int l = 0;
for (; l < r; l++)
//当前i字符串的下标为[geneStr[i].length()-r+l]
//与j字符串的下标为[l]的字符进行比较
//若相等则进行两个字符串的下一位下标对应的字符
//继续比较
//若不相等,则break
//缩小r的范围,也就是缩小需要比较字符串的范围
if (geneStr[i][geneStr[i].length() - r + l] == geneStr[j][l])
continue;
else
break;
//当l==r条件成立的时候
//即for(;l<r;l++)
//这个for循环完整的执行了
//即字符串i和字符串j在长度为r的长度,具有相等字符前缀和字符后缀
//后缀对应更长的字符串,前缀对应相对较短的字符串
//则需要记录将j字符串加在i字符串后面的长度
//因为相同长度为r,即j字符串从0到r-1下标都是相同的
if (l == r){
addLength[i][j] = geneStr[j].length() - r;
break;}}}}
// dfs(0, geneStr[i].length(), i);
// 当前遍历的层数,已经累加的长度,当前已经累加的基因片段最后一节基因片段的索引
void dfs(int now, int length, int index){
//当前累加的长度已经大于之前找到的最优解,进行剪枝
if (length > minLength)
return;
//到达叶子节点
//更新最小长度
if (now == n - 1){
minLength = length;
return;}
//枚举每个基因片段
for (int i = 0; i < n; i++){//当前基因片段没有加上去
if (!visit[i]){
visit[i] = true;dfs(now + 1, length + addLength[index][i], i);
visit[i] = false;}}}void handleData(){
//初始化访问数组,value均初始化为false
fill(visit, visit + n, false);
//将所有字符串的长度累加
//得到一个长度的最大值
//然后进行dfs
//将best进行更新
for (int i = 0; i < n; i++)
minLength += geneStr[i].length();
//预处理所有基因片段
//填充addLen数组
//将任一字符串(j)加到任一字符串(i)后面会增加的长度
//即不相等的长度(字符串j)updateLength();
//遍历所有基因片段
for (int i = 0; i < n; i++){
//将基因片段i加上去
visit[i] = true;
//从第0层开始遍历
dfs(0, geneStr[i].length(), i);
//将基因片段i撤消
visit[i] = false;}}int main(){
int scale;
//录入任务规模
scanf("%d", &scale);
for (int i = 0; i < scale; i++){scanf("%d", &n);
//初始化相关数组
visit = new bool[n];
geneStr = new string[n];
addLength = new int *[n];
for (int i = 0; i < n; i++)
addLength[i] = new int[n];
//录入基因片段
for (int i = 0; i < n; i++)
cin >> geneStr[i];
//处理基因片段
handleData();
//打印最小长度
printf("%d\n", minLength);
//释放内存
for (int i = 0; i < n; i++)
delete[] addLength[i];
delete[] addLength;
delete[] visit;
delete[] geneStr;}
return 0;}
//简洁版
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
string *geneStr;
bool *visit;
int n, minLength, **addLength;
void updateLength(){
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++){
if (i == j)
continue;
int minLen = geneStr[i].length() < geneStr[j].length() ? geneStr[i].length(): geneStr[j].length();
for (int r = minLen; r >= 0; r--){
int l = 0;
for (; l < r; l++)
if (geneStr[i][geneStr[i].length() - r + l] == geneStr[j][l])
continue;
else
break;
if (l == r){
addLength[i][j] = geneStr[j].length() - r;
break;}}}}void dfs(int now, int length, int index){
if (length > minLength)
return;
if (now == n - 1){
minLength = length;
return;}
for (int i = 0; i < n; i++){if (!visit[i]){
visit[i] = true;dfs(now + 1, length + addLength[index][i], i);
visit[i] = false;}}}void handleData(){fill(visit, visit + n, false);
for (int i = 0; i < n; i++)
minLength += geneStr[i].length();updateLength();
for (int i = 0; i < n; i++){
visit[i] = true;dfs(0, geneStr[i].length(), i);
visit[i] = false;}}int main(){
int scale;scanf("%d", &scale);
for (int i = 0; i < scale; i++){scanf("%d", &n);
visit = new bool[n];
geneStr = new string[n];
addLength = new int *[n];
for (int i = 0; i < n; i++)
addLength[i] = new int[n];
for (int i = 0; i < n; i++)
cin >> geneStr[i];handleData();printf("%d\n", minLength);
for (int i = 0; i < n; i++)
delete[] addLength[i];
delete[] addLength;
delete[] visit;
delete[] geneStr;}
return 0;}