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;
}