将包含的字符串融合,再状压dp
#include <bits/stdc++.h>
#define int long long
#define inf 4557430888798830399
#define pii pair<int,int>
#define fi first
#define se second
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
const int maxn=20,maxl=2e5+10;
using namespace std;
int n,pre[maxl];
void getpre(string& s){
pre[0]=0;
int j=0;
for(int i=1;i<s.size();i++){
while(j>0 && s[i]!=s[j]) j=pre[j-1];
if(s[i]==s[j]) j++;
pre[i]=j;
}
}
bool find(string& s,string& t){
for(int i=0,j=0;i<s.size();i++){
while(j>0 && s[i]!=t[j]) j=pre[j-1];
if(s[i]==t[j]) j++;
if(j==t.size()) return true;
}
return false;
}
int query(string& s,string& t){
int i,j;
for(i=0,j=0;i<s.size();i++){
while(j>0 && s[i]!=t[j]) j=pre[j-1];
if(s[i]==t[j]) j++;
}
return t.size()-j;
}
string s[maxn];
int f[maxn],dp[1<<maxn][maxn],ans=inf;
vector<pii> g[maxn];
void update(int& x,int y){
x=min(x,y);
}
signed main(){
cin >> n;
for(int i=0;i<n;i++){
cin >> s[i];
}
for(int i=0;i<n;i++){
getpre(s[i]);
for(int j=0;j<n;j++){
if(find(s[i],s[j])){
f[i]|=1<<j;
}
}
for(int j=0;j<n;j++){
g[i].pb(mp(j,query(s[i],s[j])));
}
}
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<n;i++){
update(dp[f[i]][i],(int)s[i].size());
}
for(int mask=0;mask<1<<n;mask++){
for(int i=0;i<n;i++){
if(dp[mask][i]==inf) continue;
for(int j=0;j<g[i].size();j++){
update(dp[mask|f[g[i][j].fi]][g[i][j].fi],dp[mask][i]+g[i][j].se);
}
}
}
for(int i=0;i<n;i++){
ans=min(ans,dp[(1<<n)-1][i]);
}
cout << ans << endl;
return 0;
}