SPOJ 7758 MGLAR10 - Growing Strings

题目链接:SPOJ7758

MGLAR10 - Growing Strings

no tags 

 

 

English Vietnamese

 

 

 

Gene and Gina have a particular kind of farm. Instead of growing animals and vegetables, as
it is usually the case in regular farms, they grow strings. A string is a sequence of characters.
Strings have the particularity that, as they grow, they add characters to the left and/or to the
right of themselves, but they never lose characters, nor insert new characters in the middle.
Gene and Gina have a collection of photos of some strings at different times during their growth.
The problem is that the collection is not annotated, so they forgot to which string each photo
belongs to. They want to put together a wall to illustrate strings growing procedures, but they
need your help to find an appropriate sequence of photos.
Each photo illustrates a string. The sequence of photos must be such that if si comes imme-
diately before si+1 in the sequence, then si+1 is a string that may have grown from si (i.e., si
appears as a consecutive substring of si+1). Also, they do not want to use repeated pictures,
so all strings in the sequence must be different.
Given a set of strings representing all available photos, your job is to calculate the size of the
largest sequence they can produce following the guidelines above.
Gene and Gina have a particular kind of farm. Instead of growing animals and vegetables, as it is usually the case in regular farms, they grow strings. A string is a sequence of characters. Strings have the particularity that, as they grow, they add characters to the left and/or to the right of themselves, but they never lose characters, nor insert new characters in the middle. 
  Gene and Gina have a collection of photos of some strings at different times during their growth.  The problem is that the collection is not annotated, so they forgot to which string each photo  belongs to. They want to put together a wall to illustrate strings growing procedures, but they  need your help to find an appropriate sequence of photos.
Each photo illustrates a string. The sequence of photos must be such that if si comes immediately before si+1 in the sequence, then si+1 is a string that may have grown from si (i.e., si appears as a consecutive substring of si+1). Also, they do not want to use repeated pictures, so all strings in the sequence must be different.
Given a set of strings representing all available photos, your job is to calculate the size of the largest sequence they can produce following the guidelines above.

 

Input

 

Each test case is given using several lines. The first line contains an integer N representing the number of strings in the set (1 ≤ N ≤ 10^4). Each of the following N lines contains a different non-empty string of at most 1000 lowercase letters of the English alphabet. Within each test case, the sum of the lengths of all strings is at most 10^6.

The last test case is followed by a line containing one zero.

 

Output

 

For each test case output a single line with a single integer representing the size of the largest sequence of photos that can be produced.

 

Sample

input
6 plant ant cant decant deca an 2 supercalifragilisticexpialidocious rag 0

output
4 2

 

 



题意:就是给出一堆字符串,问最长有多少串是可以从左到右排开,左面的是右面的字串。

题目分析:SPOJ的账号申请半天,结果一直都是申请失败,不知道为啥,,,而且网上题解少的可怜,,白瞎这么好的题了。。。。

这题主要考察AC自动机和DP,先要把每个字符串加入字典树,作为标记末尾节点的num为1。然后构造fail指针。不过仔细考察fail指针的意义就会发现我们可以在构造fail指针的时候顺便就能把答案求出来。每个fail指针指向这个字符串的最长后缀的位置。我们在每个字典树的每个节点上加一个整型sum作为以从root到这个节点的字符串为最右面的字符串时左面最多能有多少字符串(这里如果这个字符串是完整的话就把自己也加上,否则的话不用)。

这样就比较明了了。只需取其的父节点p的sum值和p->next[i]->fail节点的sum值的最大项加上自己的num即可。状态转移方程p->next[i]->sum=max(p->sum,p->next[i]->fail->sum)+p->next[i]->num;每求出一个sum都和ans取最大值。构造完fail指针这题也差不多了。

//
//  main.cpp
//  SPOJ7758
//
//  Created by teddywang on 16/4/11.
//  Copyright © 2016年 teddywang. All rights reserved.
//

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,ans,num,ptr,head,tail;
typedef struct node{
    int flag;
    int num,sum;
    node *next[26];
    node *fail;
}trienode;
trienode *root;
trienode *qu[1000006];

trienode *creat_node()
{
    trienode *r=new node;
    r->num=r->flag=r->sum=0;
    for(int i=0;i<26;i++)
        r->next[i]=NULL;
    r->fail=NULL;
    return r;
}

void init()
{
    root=creat_node();
    ans=num=ptr=0;
    head=tail=0;
}

void insert_node(char *s)
{
    trienode *r=root,*t;
    int len=strlen(s);
    for(int i=0;i<len;i++)
    {
        int buf=s[i]-'a';
        if(r->next[buf]==NULL)
        {
            t=creat_node();
            r->next[buf]=t;
            r=t;
        }
        else r=r->next[buf];
    }
    r->flag=1;r->num=1;
}

void build_ac()
{
    qu[head++]=root;
    while(tail<head)
    {
        trienode *p=qu[tail++];
        for(int i=0;i<26;i++)
        {
            if(p->next[i]!=NULL)
            {
                if(p==root)
                    p->next[i]->fail=root;
                else
                {
                    trienode *temp=p->fail;
                    while(temp!=NULL)
                    {
                        if(temp->next[i]!=NULL)
                        {
                            p->next[i]->fail=temp->next[i];
                            break;
                            //p->next[i]->num+=temp->next[i]->num;
                        }
                        else temp=temp->fail;
                    }
                    if(temp==NULL) p->next[i]->fail=root;
                }
                p->next[i]->sum=max(p->sum,p->next[i]->fail->sum)+p->next[i]->num;
                ans=max(ans,p->next[i]->sum);
                qu[head++]=p->next[i];
            }
        }
    }
}

void del(trienode *p)
{
    for(int i=0;i<26;i++)
    {
        if(p->next[i]!=NULL)
        {
            del(p->next[i]);
        }
    }
    free(p);
}

int main()
{
    while(cin>>n&&n)
    {
        init();
        for(int i=0;i<n;i++)
        {
            char s[2005];
            scanf("%s",s);
            insert_node(s);
        }
        ans=0;
        build_ac();
        
        cout<<ans<<endl;
        del(root);
    }
}

注意要释放内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值