乍看之下沒有什麼好的方法鴨.......因而考慮暴力。網絡
長度?二分彷佛可行。spa
因而咱們二分最長子串的長度(設爲$len$),藍後暴力查找。code
先在每一個串內練好後繼邊建圖blog
for(int i=1;i<=n;++i){ int len=strlen(a[i]+1); for(int j=0;j<26;++j) To[i][len][j]=-1; for(int j=len-1;j>=0;--j){ memcpy(To[i][j],To[i][j+1],sizeof(To[i][j+1])); To[i][j][a[i][j+1]-'a']=j+1; } }
每次用dfs查找一個串中長度不超過$len$的子串個數。get
一個重要的剪枝:當長度不超過$len$的子串個數已經超過n個時,顯然咱們能夠中止查找。由於顯然不管怎麼配,這個串都有解。string
如今,咱們篩掉了必定有解的串,那麼對於剩下的串咱們怎麼判斷答案爲$len$時是否有解?io
考慮暴力建出一棵trie樹,保存剩下串的信息。class
接下來咱們實現匹配。stream
首先咱們先新建總起點,終點$S,T$;以及$n-w$個點表示對應的子串(前面剪枝剪掉的子串(設爲$w$個)就不用建點辣)
(固然你能夠方便地直接開n個點)
咱們遍歷子串$k$,當訪問到樹上的某個節點$p$時,從$k$向$p$連一條流量爲1的邊(沒錯!咱們等下要跑網絡流),表示一種匹配。
全部串遍歷完後,trie上的每一個點都向$T$連一條流量爲1的邊。
最後,$S$向$n-w$個表明子串的點連一條流量爲1的邊。
因而咱們就能夠從$S$到$T$愉快地跑一遍dinic辣
找到了最短的長度,如今考慮輸出其中一種方案。
直接上dfs遍歷每個串,若是找到一個還未打上結束標記的節點,就把這個節點的結束標記打上該串的編號,而後跳出dfs,遍歷下個串。
最後開個字符棧,再跑遍dfs。
藍後就是艱難(for me)的打code了
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define stop system("pause") using namespace std; inline int min(int a,int b){return a<b?a:b;} const int inf=2147483647; #define N 305 #define M 500005 char a[N][N]; bool vis[M]; int n,ans=-1,To[N][N][27],tot,is[N]; int d[M],cur[M],S,T; int tri,p[M][27],fr[M]; int cnt,hd[M],nxt[M],ed[M],poi[M],cap[M]; queue <int> h; string b,name[N]; void clear(int x){for(int i=0;i<26;++i)p[x][i]=0;} void add(int x,int y,int v){ nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt; ed[x]=cnt; poi[cnt]=y; cap[cnt]=v; } void ins(int x,int y,int v){add(x,y,v);add(y,x,0);} #define to poi[i] bool bfs(){ memset(vis,0,sizeof(vis)); memset(d,-1,sizeof(d)); h.push(S); vis[S]=1; d[S]=0; while(!h.empty()){ int x=h.front(); h.pop(); for(int i=hd[x];i;i=nxt[i]){ if(!vis[to]&&cap[i]>0){ vis[to]=1; d[to]=d[x]+1; h.push(to); } } }return vis[T]; } int dfs(int x,int a){//dinic if(x==T||a==0) return a; int F=0,f; for(int &i=cur[x];i&&a>0;i=nxt[i]) if(d[to]==d[x]+1&&(f=dfs(to,min(cap[i],a)))>0) cap[i]-=f,a-=f,cap[i^1]+=f,F+=f; return F; } int dinic(){ int re=0; while(bfs()){ for(int i=1;i<=tri+2;++i) cur[i]=hd[i]; re+=dfs(S,inf); } return re; } void dfs1(int d,int id,int o,int dl){ if(d) ++tot; if(d==dl||tot>=n) return; for(int i=0;i<26&&tot<n;++i) if(To[id][o][i]!=-1) dfs1(d+1,id,To[id][o][i],dl); } void dfs2(int d,int id,int o,int dl,int u){ if(d) ins(id,u,1); if(d==dl) return; for(int i=0;i<26;++i) if(To[id][o][i]!=-1){ if(!p[u][i]) p[u][i]=++tri,clear(tri); dfs2(d+1,id,To[id][o][i],dl,p[u][i]); } } bool chk(int lim){ memset(ed,0,sizeof(ed)); memset(hd,0,sizeof(hd)); memset(nxt,0,sizeof(nxt)); cnt=1; tri=n+1; clear(n+1); for(int i=1;i<=n;++i){ tot=0; is[i]=0; dfs1(0,i,0,lim); if(tot<n) is[i]=1,dfs2(0,i,0,lim,n+1);//剪枝 }S=tri+1;T=tri+2; int tflow=0; for(int i=1;i<=n;++i) if(is[i]) ++tflow,ins(S,i,1); for(int i=n+1;i<=tri;++i) ins(i,T,1); return tflow==dinic(); } int dfs3(int d,int id,int o,int dl,int u){ if(d&&!fr[u]){fr[u]=id; return 1;} if(d==dl) return 0; for(int i=0;i<26;++i) if(To[id][o][i]!=-1){ if(!p[u][i]) p[u][i]=++tri,clear(tri); if(dfs3(d+1,id,To[id][o][i],dl,p[u][i])) return 1; } return 0; } void dfs4(int u){ if(fr[u]) name[fr[u]]=b; for(int i=0;i<26;++i) if(p[u][i]){ b+=(i+'a'); dfs4(p[u][i]); b.erase(b.size()-1); } } int main(){ freopen("diff.in","r",stdin); freopen("diff.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%s",a[i]+1); for(int i=1;i<=n;++i){ int len=strlen(a[i]+1); for(int j=0;j<26;++j) To[i][len][j]=-1; for(int j=len-1;j>=0;--j){ memcpy(To[i][j],To[i][j+1],sizeof(To[i][j+1])); To[i][j][a[i][j+1]-'a']=j+1; } } int l=1,r=n; while(l<r){ int mid=(l+r)/2; if(chk(mid)) r=mid; else l=mid+1; }if(!chk(l)){printf("-1");return 0;} ans=l; for(int i=1;i<=n;++i) if(is[i]) for(int j=hd[i];j;j=nxt[j]) if(cap[j]==0) fr[poi[j]]=i; for(int i=1;i<=n;++i) if(!is[i]) dfs3(0,i,0,ans,n+1); b=""; dfs4(n+1); printf("%d\n",ans); for(int i=1;i<=n;++i) cout<<name[i]<<endl; return 0; }