现在的位置: 首页 > 综合 > 正文

HDU 4271 Find Black Hand 求字串编辑距离dp

2018年01月14日 ⁄ 综合 ⁄ 共 1745字 ⁄ 字号 评论关闭

题意:给定串长<=100000的母串和n(n<=10)且长度<=10的小串,问哪一个小串在母串中通过增加删除修改一个字母的操作数(即编辑距离)最小变成
         母串中的substring,求最小的编辑距离,和对应字典序最小的字串。

题解:比赛的时候看了一眼,substring看着有点晃,就搞别的了,还是自己太弱最后没有时间仔细想想这个题目。

         对于两个串的编辑距离可以用O(n*m)的复杂度来搞,对于字串只需要做一点修改即可,具体见代码注释。
         对于长度为len的串,要想成为母串的substring最大的编辑距离不超过len。

         对于题目描述的问题,因为环的存在考虑把原串的前10位直接复制到原串后面,但是需要注意的是如果母串abcd,子串abcda,最少需要操作次数是1,
         但是将abcd复制后变成abcdabcd,abcda成了子串,答案变成了0,所以如果当前串长l*2 >= 母串长,需要循环原串起始位置暴力即可。

Sure原创,转载请注明出处。

#include <iostream>
#include <cstdio>
#include <string.h>
#define MIN(a , b) ((a) < (b) ? (a) : (b))
using namespace std;
const int inf = 1 << 29;
const int maxn = 100002;
const int maxm = 12;
char str[maxn],dtr[maxn + maxm],dic[maxm][maxm],huan[maxm];
int dp[maxn + maxm][maxm];
int m,len,llen;

int CompareString(char *s1,char *s2,int l1,int l2)  //dp[i][j]表示s2前j位作为s1串前i位的字串,且匹配的编辑距离
{
    memset(dp,0,sizeof(dp));
    //for(int i=0;i<=l1;i++)  如果这四行加上,dp[i][j]表示的是s1串前i位与s2前j位的全部匹配的编辑距离
    //{
    //    dp[i][0] = i;
    //}
    for(int i=0;i<=l2;i++)
    {
        dp[0][i] = i;
    }
    for(int i=1;i<=l1;i++)
    {
        for(int j=1;j<=l2;j++)
        {
            int cost = (s1[i-1] == s2[j-1]) ? 0 : 1;
            dp[i][j] = MIN(dp[i-1][j-1] + cost , MIN(dp[i-1][j] + 1 , dp[i][j-1] + 1));
        }
    }
    int res = inf;
    for(int i=0;i<=l1;i++)
    {
        res = MIN(res , dp[i][l2]);
    }
    return res;
}

void solve()
{
    len = strlen(str);
    strcpy(dtr , str);
    for(int i=0;i<maxm;i++)
    {
        dtr[i+len] = str[i];
    }
    llen = len + maxm;
    dtr[llen] = '\0';
    scanf("%d",&m);
    getchar();
    int pos = -1,ans = inf;
    for(int i=0;i<m;i++)
    {
        scanf("%s",dic[i]);
        int l = strlen(dic[i]);
        if((l << 1) < len)
        {
            int tmp = CompareString(dtr , dic[i] , llen , l);
            if(tmp < ans || (tmp == ans && strcmp(dic[pos] , dic[i]) > 0))
            {
                ans = tmp;
                pos = i;
            }
        }
        else
        {
            for(int s=0;s<len;s++)
            {
                for(int j=0;j<len;j++)
                {
                    huan[j] = str[(s+j) % len];
                }
                huan[len] = '\0';
                int tmp = CompareString(huan , dic[i] , len , l);
                if(tmp < ans || (tmp == ans && strcmp(dic[pos] , dic[i]) > 0))
                {
                    ans = tmp;
                    pos = i;
                }
            }
        }
    }
    printf("%s %d\n",dic[pos],ans);
    return;
}

int main()
{
    while(~scanf("%s",str))
    {
        solve();
    }
    return 0;
}

抱歉!评论已关闭.