lightoj 1013 dp

题目链接:http://lightoj.com/volume_showproblem.php?problem=1013

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int maxn = 35;
const int INF  = 0x3f3f3f;

int main()
{
    //freopen("E:\acm\input.txt","r",stdin);
    int T;
    cin>>T;
    for(int t=1;t<=T;t++){
        long long dp1[maxn][maxn],dp2[maxn][maxn];     /**  dp1[i][j] = (i+j) - num(s1中前i个和s2中前j个的最长公共子序列)。
                                                            dp2[i][j]是包含s1中前i个和s2中前j个字母的最短字符串的个数。
                                                       **/
        char s1[maxn],s2[maxn];
        scanf("%s %s",s1+1,s2+1);
        int Len1 = strlen(s1+1), Len2 = strlen(s2+1);

        for(int i=0;i<=Len1;i++)   dp1[i][0] = i, dp2[i][0] = 1;
        for(int i=0;i<=Len2;i++)   dp1[0][i] = i, dp2[0][i] = 1;

        for(int i=1;i<=Len1;i++)
           for(int j=1;j<=Len2;j++){
             if(s1[i] == s2[j]){
                   dp1[i][j] = dp1[i-1][j-1] + 1;
                   dp2[i][j] = dp2[i-1][j-1];  //这个时候直接把s1[i](s2[j])放在合成串s后面,所以加一;
                }
                  else{
                    if(dp1[i-1][j] == dp1[i][j-1]){
                        dp1[i][j] = dp1[i-1][j] + 1;
                        dp2[i][j] = dp2[i-1][j] + dp2[i][j-1];   /**这个地方最难理解,dp1[i-1][j] == dp1[i][j-1] 得出s1[i-1] != s2[j] ,s1[i] != s2[j-1].
                                                                    dp2[i-1][j] 可以理解为把s1[i]放在合成串s的最后的方法数,dp2[i][j-1]可以理解为把s2[j]放在合成串s最后的方法数。
                                                                    加起来就的到总共的组合数
                                                                 **/
                    }
                    else if(dp1[i-1][j] > dp1[i][j-1]){  //1.说明s1[i]能与s2[j-1]或者j-1之前某个组合在一起,而s2[j]不能。
                        dp1[i][j] = dp1[i][j-1] + 1;     //取小的; 并添加了一个字母s2[j];
                        dp2[i][j] = dp2[i][j-1];         //由1.这句知道:s2[j]只能添加在合成串s的最后。
                    }
                    else{                                //此处分析同上。
                        dp1[i][j] = dp1[i-1][j] + 1;     //取小的; 并添加了一个字母s1[i];
                        dp2[i][j] = dp2[i-1][j];
                    }
                }
        }
        printf("Case %d: %lld %lld
",t,dp1[Len1][Len2],dp2[Len1][Len2]);
    }
}
//总结下,这个dp1其实就是简单的LCS的变形,而dp2就是关键,这是参考别人的方法,只是觉得很精妙就学习下。
View Code
原文地址:https://www.cnblogs.com/acmdeweilai/p/3273453.html