Codeforces Similar Words [trie树+树形dp]

来源:互联网 发布:java 解析swf 编辑:程序博客网 时间:2024/06/08 02:03

题意:给你n个串,定义串A与串B相似为:A删掉第一个字符与B一样或者B删掉第一个字符与A一样,设X串中只能包含给出的n个串的所有前缀,并且不能出现相似的两个串,问S串最大为多少。

题解:我们对当前串和删掉其第一个字符的串连边(删掉一个字符的串假如不是某个串的前缀则不连边),这时候肯定生成了森林,这时候问题就转化为,在树中取不相邻节点的个数的最大值,那我们对每棵树dp取或者不取的情况即可。我们可以用tire树作为前缀的hash,建立森林。

注意:重边要去重,不然T。

AC代码:

#include<stdio.h>  #include<map>  #include<queue>  #include<string.h>#include<algorithm>  #include<vector>#include<string>#define N 1000005using namespace std;  typedef long long ll;vector<int>vt[N];int ru[N],dp[N][2],ch[N][30],mark[N];char a[N];int tot=0;int newnode(){tot++;for(int i=0;i<30;i++)ch[tot][i]=-1;return tot;}string A[N];void dfs(int u){mark[u]=1;dp[u][0]=0;dp[u][1]=1;for(int i=0;i<vt[u].size();i++){int to=vt[u][i];if(mark[to])continue;dfs(to);dp[u][0]+=max(dp[to][1],dp[to][0]);dp[u][1]+=dp[to][0];}}int main(){int T;scanf("%d",&T);while(T--){tot=0;int n;scanf("%d",&n);for(int i=0;i<30;i++)ch[0][i]=-1;for(int i=0;i<n;i++){scanf("%s",a);int l=strlen(a);A[i]=a;int now=0;for(int j=0;j<l;j++){if(ch[now][a[j]-'a']==-1)ch[now][a[j]-'a']=newnode();now=ch[now][a[j]-'a'];}}for(int i=1;i<=tot;i++)vt[i].clear(),ru[i]=0,mark[i]=0;for(int i=0;i<n;i++){int len=A[i].size();int flag=1,now1=0,now2=0;for(int j=0;j<len;j++){now1=ch[now1][A[i][j]-'a'];if(j>0){now2=ch[now2][A[i][j]-'a'];if(now2==-1)flag=0;if(flag)vt[now2].push_back(now1),ru[now1]++;}}}int ans=0;for(int i=1;i<=tot;i++)if(ru[i]==0&&mark[i]==0){dfs(i);ans+=max(dp[i][0],dp[i][1]);}printf("%d\n",ans);}}


原创粉丝点击