リンク:最短の女性ストリング
母弦の問題を求めて。SAMには適していません。
最初に問題を単純化し、指定されたn個の文字列に包含関係がないことを考慮できます。
次に、一緒にスプライスして、別の文字列または特定の文字列のサフィックスを別の文字列のプレフィックスとして使用できることを示すことができる2つの文字列のみがあります。
実際の状況はもっと複雑かもしれません。
上記の2つの状況を観察することは、ACオートマトンが同様の問題を解決するのに簡単です。
ACオートマトンで実行している場合、別の文字列のサフィックスを独自のプレフィックスとして借用できます。
ACオートマトンの確立を考えると、ACオートマトンのすべての終端ノードを通過させるパスが必要です。
もちろん、終端ノードをフェイルとするノード、またはノードをフェイルとするノードがパススルーされる特殊なケースもあります。
最短経路を見つける方法を検討してください。
これは短絡の問題であることがわかります。最短ルートを階層化グラフとして実行します。
上記の2つのケースは、ACオートマトンのトライグラフ上で実行されているため、満足できます。
辞書式順序を考慮して、最小の辞書式順序を持つノードを毎回選択します。
ノードxで表されるすべての終了ノードのセットを表すには、s [x]配列を前処理する必要があることに注意してください。失敗ポインタのsを渡すことができることに注意してください。
const int MAXN=610,maxn=1<<12;
int n,cnt,maxx;
char a[13][MAXN],b[MAXN],ans[MAXN];
int s[MAXN],q[1500010],vis[MAXN][maxn],pre[MAXN][maxn],w[1500010];
struct wy{int ch[26];int fail;}t[MAXN];
inline void insert(int x)
{
int len=strlen(a[x]+1);
int p=0;
rep(1,len,i)
{
int w=a[x][i]-'A';
if(!t[p].ch[w])t[p].ch[w]=++cnt;
p=t[p].ch[w];b[p]=a[x][i];
}
s[p]=s[p]|(1<<(x-1));
}
inline void get_fail()
{
int l=0,r=0;
rep(0,25,i)if(t[0].ch[i])q[++r]=t[0].ch[i];
while(++l<=r)
{
int x=q[l];
rep(0,25,i)
{
int tn=t[x].ch[i];
if(tn)fail(tn)=t[fail(x)].ch[i],s[tn]|=s[t[fail(x)].ch[i]],q[++r]=tn;
else t[x].ch[i]=t[fail(x)].ch[i];
}
}
}
inline void bfs()
{
int l=0,r=0;q[++r]=0;
vis[0][0]=0;w[r]=0;
while(++l<=r)
{
int x=q[l];
int xx=w[l];
rep(0,25,i)
{
int tn=t[x].ch[i];
if(tn)
{
int ss=s[tn]|xx;
if(vis[tn][ss]==-1)
{
pre[tn][ss]=l;
vis[tn][ss]=vis[x][xx]+1;
q[++r]=tn;w[r]=ss;
if(ss==maxx)
{
int w1=tn,w2=ss;
while(vis[tn][ss])
{
ans[vis[tn][ss]]=b[w1];
--vis[tn][ss];
int s1=q[pre[w1][w2]];
int s2=w[pre[w1][w2]];
w1=s1;w2=s2;
}
printf("%s",ans+1);
return;
}
}
}
}
}
}
int main()
{
freopen("1.in","r",stdin);
gt(n);maxx=(1<<n)-1;
rep(1,n,i)gc(a[i]),insert(i);
get_fail();
memset(vis,-1,sizeof(vis));
bfs();return 0;
}