整齐打印与编辑距离问题

整齐打印

使用等宽字符打印一段文本。输入文本为n个单词的序列,单词长度为$l_1,l_2, cdots l_n$个字符,将其打印在若干行上,每一行最多$Maxnum$个字符。
如果某行包含第$i$到第$j(i leq j)$个单词,行尾额外空格符的数量是$M-j+i-sum_{k=i}^jl_k$,这个值必须是非负的。

算法分析:

图片描述

图片描述

图片描述

实现过程:

print_neatly.h

#include <iostream>
#include <string.h>

#define infinity 0x7fffffff

using namespace std;
int get_lines(int solution[],int j,string number[]);

void print_neatly(int length[],string number[],int n,int Maxnum)
{
    int i,j;

    //保存空格数
    int **space;
    space=new int *[n+1];
    for(int i=0;i<=n;i++)
    {
        space[i]=new int [n+1];
    }


    //保存立方值
    int **cube;
    cube=new int *[n+1];
    for(int i=0;i<=n;i++)
    {
        cube[i]=new int [n+1];
    }

    //用于保存解决方案
    int *solution=new int [n+1];

    //初始化获取space[][]的值
    for(int i=1;i<=n;i++)
    {
        space[i][i]=Maxnum-length[i-1];  //这里space[i][]表示第几个数?length[i-1]对应的是下标
        for(int j=i+1;j<=n;j++)
            space[i][j]=space[i][j-1]-length[j-1]-1;
    }

    //获取cube的值,整齐打印是依据cube的值来确定打印距离
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            if(space[i][j]<0)
                cube[i][j]=infinity;
            else if(j==n && space[i][j]>=0)
                cube[i][j]=0;
            else
                cube[i][j]=space[i][j]*space[i][j]*space[i][j];
        }
    }

    //动态规划过程,将结果存储在res数组中
    int *res=new int [n+1];
    res[0]=0;

    for(int j=1;j<=n;j++)
    {
        res[j]=infinity;
        for(int i=1;i<=j;i++)
        {
            if(res[i-1]!=infinity && cube[i][j]!=infinity && (res[i-1]+cube[i][j]<res[j]))
            {
                res[j]=res[i-1]+cube[i][j];
                solution[j]=i;    //i为当前行的第一个元素
            }
        }
    }

    get_lines(solution,n,number);

    //释放内存
    delete[] res;

    delete[] solution;

    for(int i=0;i<=n;i++)
        delete[] cube[i];
    delete[] cube;

    for(int i=0;i<=n;i++)
        delete[] space[i];
    delete[] space;
}

int get_lines(int solution[],int j,string number[])  //j为当前行的最后一个元素下标
{
    int k;
    int i=solution[j];

    if(i==1)  //表示第一个元素
        k=1;
    else
        k=get_lines(solution,i-1,number)+1;  //递归
    cout<<"current line number is : "<<k<<" ";

    for(int l=i;l<=j;l++)
        cout<<number[l-1]<<" ";  //当前行的第l个元素,str下标为l-1
    cout<<endl;
    return k;
}

print_neatly.cpp

#include "print_neatly.h"

int main()
{
    int n=10;  //10个单词
    int Maxnum=8;  //一行可以容纳最多8个字符
    string number[n]={"abc","def","gh","polq","cs","opaqe","klfgh","t","asd","th"};
    int length[n]={0};

    for(int i=0;i<n;i++)
    {
        length[i]=number[i].size();
    }
    print_neatly(length,number,n,Maxnum);
    return 0;
}

编辑距离

算法分析

图片描述

图片描述

图片描述

图片描述

状态转移函数

$$res[i,j]=min
begin{cases}
res[i-1,j-1]+copy& text{x[i]==y[j]}\
res[i-1,j-1]+replace& text{x[i]!=y[j]}\
res[i-2,j-2]+twiddle& text{i,j>=2 x[i]==y[j-1] && x[i-1]==y[j]}\
res[i-1,j]+delete& text{other}\
res[i,j-1]+insert& text{other}\
mathop{min}_{0 leq i leq m} {res[i,n]}+kill& text{i==m && j==n}
end{cases}$$

分析方法与“最长公共子序列”问题分析的方法类似。

count_distance.h

#include <iostream>
using namespace std;

#define infinity 0x7fffffff


enum {COPY,REPLACE,DELETE,INSERT,TWIDDLE,KILL,TYPE_NUM};

struct TABLE
{
    int **res,**solution;
    TABLE(int m,int n)  //res[m][n] 分别表示图中x_max和y_max
    {
        res=new int *[m+1];
        for(int i=0;i<=m;i++)
            res[i]=new int [n+1];

        solution=new int *[m+1];
        for(int i=0;i<=m;i++)
            solution[i]=new int [n+1];
    }
};

void PRINT_SOLUTION(TABLE distance,int i,int j);

TABLE count_distance(char x[],char y[],int m,int n)
{
    TABLE distance(m,n);
    int cost[TYPE_NUM]={-1,1,2,3,4,-2};

    //初始化
    distance.res[0][0]=0;
    for(int i=0;i<=m;i++)
    {
        distance.res[i][0]=i*cost[DELETE];  //这里不操作y,等于把x中的元素全部删除
        //删除的代价就是 第几个元素×cost
        distance.solution[i][0]=DELETE;
    }
    for(int j=0;j<=n;j++)
    {
        //这里相当于x中没有元素,y[]的值等于插入每一个新的元素
        distance.res[0][j]=j*cost[INSERT];
        distance.solution[0][j]=INSERT;
    }

    //计算最优代价
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
        {
            distance.res[i][j]=infinity;
            if(x[i]==y[j] && distance.res[i-1][j-1]+cost[COPY]<distance.res[i][j])
            {
                distance.res[i][j]=distance.res[i-1][j-1]+cost[COPY];
                distance.solution[i][j]=COPY;
            }
            if(x[i]!=y[j] && distance.res[i-1][j-1]+cost[REPLACE]<distance.res[i][j])
            {
                distance.res[i][j]=distance.res[i-1][j-1]+cost[REPLACE];
                distance.solution[i][j]=REPLACE;
            }
            if(i>=2&&j>=2&& x[i]==y[j-1] && x[i-1]==y[j] && distance.res[i-2][j-2]+cost[TWIDDLE]<distance.res[i][j])
            {
                distance.res[i][j]=distance.res[i-2][j-2]+cost[TWIDDLE];
                distance.solution[i][j]=TWIDDLE;
            }
            if(distance.res[i-1][j]+cost[DELETE]<distance.res[i][j])
            {
                distance.res[i][j]=distance.res[i-1][j]+cost[DELETE];
                distance.solution[i][j]=DELETE;
            }
            if(distance.res[i][j-1]+cost[INSERT]<distance.res[i][j])
            {
                distance.res[i][j]=distance.res[i][j-1]+cost[INSERT];
                distance.solution[i][j]=INSERT;
            }
        }
    }

    //此时序列y[n]的值已经完成,这个时候截取从0<=i<=m-1中最小的kill值
    //把m以后的值全部截取掉
    for(int i=0;i<=m-1;i++)
    {
        if(distance.res[i][n]+cost[KILL]<distance.res[m][n])  //相当于调整res[m][n]的值
        //判断从哪里开始截断?
        {
            distance.res[m][n]=distance.res[i][n]+cost[KILL];
            distance.solution[m][n]=i;
            //从i开始截断,distance.solution[][]提供回溯的点,回溯到哪个点?
        }
    }
    cout<<"distance[m][n]="<<distance.res[m][n]<<" "<<endl;

    //输出:
    for(int i=0;i<=m;i++)
    {
        for(int j=0;j<=n;j++)
            cout<<distance.res[i][j]<<" ";
        cout<<endl;
    }
    cout<<endl;

    for(int i=0;i<=m;i++)
    {
        for(int j=0;j<=n;j++)
            PRINT_SOLUTION(distance,i,j);
        cout<<endl;
    }
    cout<<endl;

    return distance;
}

void PRINT_sequence(TABLE distance,int i,int j)
{
    int I,J;
    if(i==0 && j==0)
        return;
    if(distance.solution[i][j]==COPY || distance.solution[i][j]==REPLACE)
    {
        I=i-1;
        J=j-1;
    }
    else if(distance.solution[i][j]==TWIDDLE)
    {
        I=i-2;
        J=j-2;
    }
    else if(distance.solution[i][j]==DELETE)
    {
        I=i-1;
        J=j;
    }
    else if(distance.solution[i][j]==INSERT)
    {
        I=i;
        J=j-1;
    }
    else
    {
        I=distance.solution[i][j];
        J=j;
        distance.solution[i][j]=KILL;
    }
    PRINT_sequence(distance,I,J);
    PRINT_SOLUTION(distance,i,j);
}

void PRINT_SOLUTION(TABLE distance,int i,int j)
{
    if(distance.solution[i][j]==COPY)
        cout<<"COPY"<<" ";
    else if(distance.solution[i][j]==REPLACE)
        cout<<"REPLACE"<<" ";
    else if(distance.solution[i][j]==INSERT)
        cout<<"INSERT"<<" ";
    else if(distance.solution[i][j]==TWIDDLE)
        cout<<"TWIDDLE"<<" ";
    else
        cout<<"KILL"<<" ";
}

count_distance.cpp

#include "count_distance.h"
#include <string.h>

using namespace std;

int main()
{
    char x[]="algorithm";
    char y[]="altruistic";
    int x_len=strlen(x),y_len=strlen(y);
    TABLE distance=count_distance(x,y,x_len,y_len);
    PRINT_sequence(distance,x_len,y_len);
}

算法实现结果

图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值