uva 10029 - Edit Step Ladders

Problem C: Edit Step Ladders


An  edit step  is a transformation from one word  x  to another word  y  such that  x  and  y  are words in the dictionary, and  x  can be transformed to  y  by adding, deleting, or changing one letter. So the transformation from  dig  to  dog  or from  dog  to  do  are both edit steps. An  edit step ladder  is a lexicographically ordered sequence of words  w1, w2, ... wn  such that the transformation from  wi  to  wi+1  is an edit step for all  i  from 1 to  n-1 .

For a given dictionary, you are to compute the length of the longest edit step ladder.

Input

The input to your program consists of the dictionary - a set of lower case words in lexicographic order - one per line. No word exceeds 16 letters and there are no more than 25000 words in the dictionary.

Output

The output consists of a single integer, the number of words in the longest edit step ladder.

Sample Input

cat
dig
dog
fig
fin
fine
fog
log
wine

Sample Output

5

这道题说白了就是LIS,复杂度为O(nlogn),因为字符串是按字典序方式组成LIS的。

dp[i]表示以第i个字符串结尾的阶梯的最大长度。

dp[i]=max{dp[j]+1},1<=j<i&&s[j]可以变换得到s[i],显然j必须通过O(logn)的算法得到,否则必TLE。

这里一个字符串能否由之前的字符串变换得到,只能用暴力变换了。可以证明s[j]->s[i],那么一定有s[i]->s[j];

既然这样我们就从s[i]出发进行三种变换,当然不能变换成字典序增大的字符串,因此要适当剪枝。不然的话,

1个字符串可以变换出16+26*16+26*16个新字符串,那么这个数再乘上nlogn(n最大25000),复杂度也是不能接受的。

关于logn得到j可以采用字符串哈希或者二分查找得到,我采用的是二分查找。


代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define Maxn 25010
using namespace std;

char s[Maxn][20];
char tmp[20];
int len,tot,id,dp[Maxn];
struct cmp{
    bool operator()(const char *a,const char *b)const{
        return strcmp(a,b)<0;
    }
};
void del(int x){
    int j=0;
    for(int i=0;i<len;i++)
        if(i!=x) tmp[j++]=s[tot-1][i];
    tmp[j]='\0';
}
void insert(int x,char t){
    int j=0;
    for(int i=0;i<x;i++)
        tmp[j++]=s[tot-1][i];
    tmp[j++]=t;
    for(int i=x;i<len;i++)
        tmp[j++]=s[tot-1][i];
    tmp[j]='\0';
}
void replace(int x,char t){
    int j=0;
    for(int i=0;i<=len;i++)
        tmp[j++]=s[tot-1][i];
    tmp[x]=t;
}
int main()
{
    int ans=1;
    for(int i=0;i<Maxn;i++) dp[i]=1;
    while(~scanf("%s",s[tot++])){
        len=strlen(s[tot-1]);
        for(int i=0;i<len;i++) //删除
            if(s[tot-1][i]>=s[tot-1][i+1]){
                del(i);
                id=lower_bound(s,s+tot,tmp,cmp())-s;
                if(id!=tot&&!strcmp(s[id],tmp))
                    dp[tot-1]=max(dp[tot-1],dp[id]+1);
            }
        for(int i=0;i<len;i++) //插入
            for(char j='a';j<=s[tot-1][i];j++){
                insert(i,j);
                id=lower_bound(s,s+tot,tmp,cmp())-s;
                if(id!=tot&&!strcmp(s[id],tmp))
                    dp[tot-1]=max(dp[tot-1],dp[id]+1);
            }
        for(int i=0;i<len;i++) //替换
            for(char j='a';j<s[tot-1][i];j++){
                replace(i,j);
                id=lower_bound(s,s+tot,tmp,cmp())-s;
                if(id!=tot&&!strcmp(s[id],tmp)){
                    dp[tot-1]=max(dp[tot-1],dp[id]+1);
                    ans=max(ans,dp[tot-1]);
                }
            }
    }
    printf("%d\n",ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值