• DP在字符匹配上的实现


    在此保存下近段时间做的DP在字符匹配上的实现的题目

    对于不同的字符串来说,2者只能不断将下标往后推移来实现匹配从而得到的最大匹配数

    如 abcd 和 dcba 这个最大匹配数只能为1,因为两个d匹配后,在第一个字符串中是不能再拿前面的字符进行匹配的(当然你要是匹配a,b,c也是一样的道理)

    对于每一道题目若想不断找到那个匹配成功的字符的话,我们需要一个函数不断递归找到前一个匹配成功的字符,这里引进一个T[N][N]的标志位来帮助我们判断何时进行递归

    这里的题都是有关这个的形式

    1.POJ 1458http://vjudge.net/problem/viewProblem.action?id=17083

    这就是最基本的2个字符串的最大匹配数

    dp[i][j]代表前一个字符串取i位,后一个字符串取j位时得到的最大匹配数

    DP 方程:dp[i][j]={dp[i-1][j-1]+1,a[i]==b[j] | max(dp[i-1][j],dp[i][j-1])}

    自己一开始在做题时写成了dp[i][j]={dp[i-1][j-1]+1,a[i]==b[j] | max(dp[i][j],dp[i-1][j-1])}

    这样仔细想想很容易发现dp[i][j]=max(dp[i][j],dp[i-1][j-1]) 只是考虑了一部分的状态,而且本身在i,j2次循环时dp[i][j]也只出现了一次,也就是说只

    进行了一次赋值操作,根本就不会进行更新操作

    dp[i][j]=max(dp[i-1][j],dp[i][j-1])却可以在循环中不断将前面得到的最大值赋给后面;

     for(int j=1;j<=lb;j++)
                    if(a[i-1]==b[j-1])
                    {
                        dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
                    }
                    else dp[i][j]=max(dp[i][j-1],dp[i-1][j]);//这一段要注意,这是为了匹配到2段数组均在小于它的情况下所得
            }
    总代码如下:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define N 1001
    #define max(a,b) a>b?a:b;
    int dp[N][N];
    char a[N],b[N];
    
    int main()
    {
        while(scanf("%s%s",a,b)!=EOF){
            memset(dp,0,sizeof(dp));
            int la=strlen(a),lb=strlen(b);
            for(int i=1;i<=la;i++){
                for(int j=1;j<=lb;j++)
                    if(a[i-1]==b[j-1])
                    {
                        dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
                    }
                    else dp[i][j]=max(dp[i][j-1],dp[i-1][j]);//这一段要注意,这是为了匹配到2段数组均在小于它的情况下所得
            }
            printf("%d
    ",dp[la][lb]);
        }
        return 0;
    }
    View Code

    但是我们想要不断找到那个匹配成功的字符的话,我们需要一个函数不断递归找到前一个匹配成功的字符,这里引进一个T[N][N]的标志位来帮助我们判断何时进行递归

    这是递归函数

     1 void output(int len1,int len2)
     2 {
     3     if(len1==0||len2==0) return;
     4     if(T[len1][len2]==1){
     5         output(len1-1,len2-1);
     6         printf("%c
    ",a[len1-1]);
     7     }
     8     else if(T[len1][len2]==2) output(len1-1,len2);
     9     else output(len1,len2-1);
    10 }

    这是T[][]在进行寻找最长子序列时进行赋值

    在第二题中要用到这个方法,就不再详述

    2.POJ 2250

    http://vjudge.net/problem/viewProblem.action?id=17325

    这与上面不同的是这是给2堆字符串,找其中尽可能多的相同的字符串并输出

    这里需要用到output(int,int)进行递归调用

    总代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 using namespace std;
     6 #define N 103
     7 string a[N],b[N];
     8 int dp[N][N],T[N][N],len1,len2,cnt=0;
     9 
    10 void match(int len1,int len2)
    11 {
    12     memset(dp,0,sizeof(dp));
    13     for(int i=1;i<=len1;i++)
    14     {
    15         for(int j=1;j<=len2;j++)
    16         {
    17             if(a[i-1]==b[j-1]) dp[i][j]=dp[i-1][j-1]+1,T[i][j]=1;
    18             else{
    19                 if(dp[i-1][j]>dp[i][j-1]) dp[i][j]=dp[i-1][j],T[i][j]=2;
    20                 else dp[i][j]=dp[i][j-1],T[i][j]=3;
    21             }
    22         }
    23     }
    24 }
    25 void output(int m,int n)
    26 {
    27     if(m==0||n==0) return;
    28     if(T[m][n]==1){
    29         output(m-1,n-1);
    30         cnt++;
    31         if(cnt==dp[len1][len2])
    32             cout<<a[m-1]<<endl;
    33         else cout<<a[m-1]<<' ';
    34     }
    35     else if(T[m][n]==2) output(m-1,n);
    36     else output(m,n-1);
    37 }
    38 int main()
    39 {
    40     string str;
    41     while(cin>>str)
    42     {
    43         len1=1,len2=0;
    44         a[0]=str;
    45         while(cin>>str&&str.at(0)!='#'){
    46             a[len1++]=str;
    47         }
    48         while(cin>>str&&str.at(0)!='#'){
    49             b[len2++]=str;
    50         }
    51         match(len1,len2);
    52         output(len1,len2);
    53         //cout<<dp[len1][len2]<<endl;
    54     }
    55     return 0;
    56 }
    View Code
  • 相关阅读:
    [转载]Back up all of your mysql databases nightly
    编写windows7 bat运行脚本
    Windows7开通Internet信息服务
    【LeetCode题解】7_反转整数
    【LeetCode题解】350_两个数组的交集Ⅱ
    【LeetCode题解】349_两个数组的交集
    【LeetCode题解】94_二叉树的中序遍历
    【LeetCode题解】144_二叉树的前序遍历
    【LeetCode题解】2_两数相加
    【LeetCode题解】530_二分搜索树的最小绝对值差
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/3881335.html
Copyright © 2020-2023  润新知