POJ2146 Confusing Login Names [最小字符串编辑距离]

  给出一个字符串S1和S2,可以对S1进行添加字符(insert),删除字符(delete),替换字符(replace),交换相邻字符(swap)四种操作,问是否能在dis步骤内将S1转换成S2。

  用d[i][j]表示将S1[1..i]转化为S2[1..j]的最小步数。

  这几种操作可以表示为:添加d[i][j]=d[i][j-1]+1,删除d[i][j]=d[i-1][j]+1,替换d[i][j]=d[i-1][j-1]+1,交换d[i][j]=d[i-2][j-2]+1(条件为s1[i-1]==s2[j]&s1[i]==s2[j-1])。

  但是仅考虑到这些还是过不了这道题的,因为交换操作可以减少其它操作的步数,比如说S1="ca",S2="abc",可以通过先swap(c,a),然后在中间insert(b),这样2步就可以由S1转化到S2,也就是说d[i][j]=d[i-2][j-3]+2。当S1="abc",S2="ca"时,可以先delete(b),然后再swap(a,c)变成2,也就是说d[i][j]=d[i-3][j-2]+2。实质是通过insert和delete辅助swap完成了不相邻的两个数的交换。这题中的dis范围是2,最多也只能操作两次,一开始没注意这个条件,还想了好久。。。

  最后的DP方程大概就是,具体的条件看代码就清楚了。

#include <cstdio>
#include <string.h>
#include <algorithm>
#define INF 0x3fffffff
using namespace std;
struct cstr{
    char s[22];
    bool operator <(const cstr& c)const{
        return strcmp(s,c.s)<0;
    }
}st[205];
int n,dis,d[20][20];
int dp(char *s1,char *s2){
    int l1=strlen(s1),l2=strlen(s2);
    memset(d,0,sizeof d);
    for(int i=1;i<=l2;i++)d[0][i]=i;
    for(int i=1;i<=l1;i++)d[i][0]=i;
    for(int i=1;i<=l1;i++){
        for(int j=1;j<=l2;j++){
            d[i][j]=INF;
            if(s1[i-1]==s2[j-1]){
                d[i][j]=d[i-1][j-1];
            }else{
                d[i][j]=min(d[i][j-1],min(d[i-1][j],d[i-1][j-1]))+1;
            }
            if(i>=2&&j>=2&&s1[i-2]==s2[j-1]&&s1[i-1]==s2[j-2]){
                d[i][j]=min(d[i][j],d[i-2][j-2]+1);
            }
            if(i>=2&&j>=3&&s1[i-2]==s2[j-1]&&s1[i-1]==s2[j-3]){
                d[i][j]=min(d[i][j],d[i-2][j-3]+2);
            }
            if(i>=3&&j>=2&&s1[i-1]==s2[j-2]&&s1[i-3]==s2[j-1]){
                d[i][j]=min(d[i][j],d[i-3][j-2]+2);
            }
        }
    }
    return d[l1][l2];
}

int main(){
   // freopen("test.in","r",stdin);
    while(scanf("%d",&n),n){
        scanf("%d",&dis);
        for(int i=0;i<n;i++)scanf("%s",st[i].s);
        sort(st,st+n);
        int tot=0;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                int x=dp(st[i].s,st[j].s);
                if(x<=dis){
                    tot++;
                    printf("%s,%s\n",st[i].s,st[j].s);
                }
            }
        }
        printf("%d\n",tot);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/swm8023/p/2619946.html