SPOJ - 2325 【String Distance】 【dp、剪枝】

来源:互联网 发布:mac os qq 远程协助 编辑:程序博客网 时间:2024/06/08 09:28

Description

Let A = a1a2...ak and B = b1b2...bl be strings of lengths k and l, respectively. The string distance between A and B is defined in the following way (d[i,j] is the distance of substrings a1...ai and b1...bj, where 0 ≤ i ≤ k and 0 ≤ j ≤ l -- i or j being 0 represents the empty substring). The definition for d[i, j] is d[0, 0] = 0 and for (i, j) ≠ (0, 0) d[i, j] is the minimum of all that apply:

  • d[i, j - 1] + 1, if j > 0
  • d[i - 1, j] + 1, if i > 0
  • d[i - 1, j - 1], if i > 0, j > 0, and ai = bj
  • d[i - 1, j - 1] + 1, if i > 0, j > 0, and ai ≠ bj
  • d[i - 2, j - 2] + 1, if i ≥ 2, j ≥ 2, ai = bj-1, and ai-1 = bj

The distance between A and B is equal to d[k,l].

For two given strings A and B, compute their distance knowing that it is not higher than 100.

Input

In the first line, k and l are given, giving the lengths of the strings A and B (1 ≤ k, l ≤ 105). In the second and third lines strings A and B, respectively, are given. A and B contain only lowercase letters of the English alphabet.

Output

In the first line, write one number, the distance between A and B, followed by a newline.

Sample Input

Input:8 8computerkmpjutreOutput:4

【FinkyS】

这道题,题目都把规律全给出来了,用dp直接可以做出来,但是肯定会超时,所以毋庸置疑是一个dp的优化问题。由题目可知,要求每项的dp,最多只需知道前两项,所以实现的时候可以用滚动数组,这样可以防止MLE,但是怎么对o(k*l)进行优化呢,观察到题目给出一个已知条件“最终结果不会大于100”,优化肯定是从这里下手。但是想了半天想不出来,后来看大神的题解,说用剪枝。都说“由于最终结果不大于100,所以每一层dp的范围不超过前后100个元素”,我想了很久还是想不明白为什么。后来自己随便拿一组数据输出dp矩阵图来观察规律,后来发现,如果结果值dp[k][l]的值为result,且result来自dp[k][l-1]那么dp[k][l-1]的值必为result-1,再下去,如果dp[k][l-1]的值来自dp[k][l-2],那么dp[k][l-2]的值必为result-2,那么题目给出result的值不大于100,那么只需知道当i=k时(l>100),只需知道dp[k][l-100]~dp[k][l-1]的值,因为假设要用到dp[k][l-101]的值,那么dp[k][l-101]的值必为100-101= -1,显然这是不可能的,所以不需要知道dp[k][0]~dp[k][l-100]的值,可以将其剪掉。同样,当i=k-1时,可以观察出只需知道dp[i][l-100+k-i]~dp[i][l-1]的值。同样如果result的值来自dp[k-1][l]那么跟上同样的步骤,最多只需知道dp[k-100][l]的值。最后把这些不需要知道的数据剪掉最后o(k*l)就变成o(k*l - (k-100)(l-100) )=o(100*(k+l)-10000) (k,l>100),最后提交通过。

下面是剪枝后的dp矩阵图:假设已知结果不大于15



【实现代码】


#include<stdio.h>#include<string.h>#include<stdlib.h>#define INF 0x7FFFFFFF#define N 100int dp[3][100005],mod[100005];char a[100005],b[100005];int MIN(int x,int y){ return x<y?x:y; }int main(){    int l,k,i,j,temp;//    char STD[102400]="";//    freopen("in.txt","r",stdin);//    fread(STD,1,1024,stdin);//    printf("===input===\n%s\n===output===\n",STD);//    freopen("in.txt","r",stdin);    for(i=0;i<100005;i++) mod[i]=i%3;    while(scanf("%d%d",&k,&l)>0)    {        scanf("%s%s",a+1,b+1);        if(strlen(a)-strlen(b)>=N){ printf("%d\n",N); continue; }        if(strlen(b)-strlen(a)>=N){ printf("%d\n",N); continue; }        for(i=0;i<=l;i++) dp[0][i]=i;        for(i=1;i<=k;i++)        {            if(i>=N)j=i-N;            else j=0;//            for(int shit=0;shit<i-N;shit++)printf("   ");            for(;j<=l;j++)            {//                if(j-i>N){printf("   ");continue;}                if(j-i>N)break;                temp=INF;                if(j-i!=N)temp=MIN(temp,dp[mod[i-1]][j]+1);                if(j>0&&i-j!=N) temp=MIN(temp,dp[mod[i]][j-1]+1);                if(j>0)                {                    if(a[i]==b[j]) temp=MIN(temp,dp[mod[i-1]][j-1]);                    else temp=MIN(temp,dp[mod[i-1]][j-1]+1);                    if(i>=2&&j>=2&&a[i]==b[j-1]&&a[i-1]==b[j]) temp=MIN(temp,dp[mod[i-2]][j-2]+1);                }                dp[mod[i]][j]=temp;//                printf("%.2d ",temp);            }//            printf("\n");        }        printf("%d\n",dp[mod[k]][l]);    }    return 0;}