For a given dictionary, you are to compute the length of the longest edit step ladder.
cat dig dog fig fin fine fog log wine
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; }