首先感谢某些大神帮我解决此题
我们可以把所有的长度为前缀,后缀建字典树
对于字典树深度为k的节点,可以合并在这个节点上的字符串
那么这样想,一个字符串连接的是字典树的两个节点(自己的前缀和后缀),然后对于字符串连的每一条边,都至少有一个点要被选中
那么相当于在一张图上跑最小点覆盖集
此时我就不会了。。。跑去问,然后得到回复“这是一张二分图”
为什么呢?我们可以把所有前缀放在一边,后缀放在另外一边,分开建字典树
每一个字符串当做一条边,连接自己的前缀和后缀
这样就变成二分图了,跑最大匹配(其实是最小点覆盖)就好了
网络流反边写挂,wa*2
代码
//Copyright(c)2016 liuchenrui #include<bits/stdc++.h> #define inf 1000000000 using namespace std; inline void splay(int &v){ v=0;char c=0;int p=1; while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();} while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();} v*=p; } struct Edge{ int to,next;int flow; }edge[100010]; int first[10005],size; int deep[10005],dl[10005]; void addedge(int x,int y,int z){ size++; edge[size].to=y; edge[size].next=first[x]; first[x]=size; edge[size].flow=z; } void add(int x,int y,int z){ addedge(x,y,z),addedge(y,x,0); //if(z)printf("%d %d\n",x,y); } int aim; int dfs(int now,int flow){ if(now==aim)return flow; int F=0; for(int u=first[now];u&&flow;u=edge[u].next){ if(deep[edge[u].to]==deep[now]+1&&edge[u].flow){ int tmp=dfs(edge[u].to,min(flow,edge[u].flow)); F+=tmp;edge[u].flow-=tmp;edge[u^1].flow+=tmp;flow-=tmp; } } if(!F)deep[now]=-5; return F; } bool bfs(int S,int T){ memset(deep,0,sizeof(deep)); dl[1]=S;deep[S]=1; int head=0,tail=1; while(head!=tail){ head++; for(int u=first[dl[head]];u;u=edge[u].next){ if(!deep[edge[u].to]&&edge[u].flow){ dl[++tail]=edge[u].to; deep[edge[u].to]=deep[dl[head]]+1; } } } return deep[T]; } int maxflow(int S,int T){ int ret=0;aim=T; while(bfs(S,T)){ ret+=dfs(S,inf); } return ret; } int n,k; struct Trie{ int t[1500000][26],tot; int a[10010];map<int,int>f; int insert(char *s,int id){ int now=0; for(int i=1;i<=k;i++){ if(!t[now][s[i]-'A']){ t[now][s[i]-'A']=++tot; } now=t[now][s[i]-'A']; } f[now]=1;a[id]=now; } void ls(){ int cnt=0; for(map<int,int>::iterator it=f.begin();it!=f.end();++it){ it->second=++cnt; } for(int i=1;i<=n;i++)a[i]=f[a[i]]; } }A,B; char s[100010]; int main(){ freopen("heavy.in","r",stdin); freopen("heavy.out","w",stdout); splay(n),splay(k); for(int i=1;i<=n;i++){ scanf("%s",s+1); A.insert(s,i); int len=strlen(s+1); reverse(s+1,s+len+1); B.insert(s,i); } A.ls(),B.ls();size=1; int x=A.f.size(),y=B.f.size(); int S=0,T=x+y+1; for(int i=1;i<=x;i++){ add(S,i,1); } for(int i=1;i<=y;i++){ add(i+x,T,1); } for(int i=1;i<=n;i++){ add(A.a[i],B.a[i]+x,1); } //cerr<<x<<" "<<y<<endl; printf("%d\n",maxflow(S,T)); }