UVALive 6697 - Homework Evaluation(dp,字符串匹配得分)

来源:互联网 发布:apache ab测试百度 编辑:程序博客网 时间:2024/05/07 00:59

题目链接:
UVALive 6697 - Homework Evaluation
题意:
给出两个字符串,用第二个去匹配第一个字符串,第二个字符串中的字母可以看成:新插入的,有丢失的,正确匹配的,不正确的。

  • 正确的+8分
  • 错误的-5分
  • 插入或删除一个字母-3分
  • 连续插入或删除额外扣除-4分

例如:
Whatagreatisl/andtovisit            gr//tisllamd/
应用上面的规则可以得到的分数是:
8851334264598=42
现在给出两个字符串(第一个长度不大于100,第二个长度不大于50),问最优得分是多少?

分析:
dp
我们可以发现第二个字符串的每个字母要么和第一个字符串的某个字母匹配,要么看成是插在第一个字符串的某个字母前面。

  • dp[0][i][j]表示第二个字符串的第i个字母和第一个字符串的第j个字母匹配时,前i个字母的得分
  • dp[1][i][j]表示第二个字符串的第i个字母插在第一个字符串的第j个字母前面时,前i个字母的得分

考虑状态转移方程。设字符串的下标都是从1开始,第一个字符串为s[],第二个字符串为ss[]

  • 考虑初始化。
memset(dp, 0, sizeof(dp));if( i > 1) dp[0][i][1] = -3 * (i - 1) - 4;if(ss[i] == s[1]) dp[0][i][1] += 8;else dp[0][i][1] -= 5;dp[1][i][1] = -i * 3 - 4;dp[0][i][0] = dp[1][i][0] = -inf; 
  • 当第二个字符串的第i和第一个字符串的第j个匹配时,遍历第一个字符串的前j个字母,考虑第二个字符串的第i1个字母的匹配位置k,先初始化dp[0][i][j]=inf
    对于dp[0][i][j],也就是恰好ij
    • 如果k<j1,如果第i1个也和第k个恰好匹配(从dp[0][i1][k]转移),那么就相当于在第i个和第i1个之间连续删除了(jk1),所以
      dp[0][i][j]=max(dp[0][i][j],dp[0][i1][k]3(jk1)4);
      如果第i1个插入在第k个之前(从dp[1][i1][k]转移),那么就相当于在第i个和第i1个之间连续删除了jk,所以有:
      dp[0][i][j]=max(dp[0][i][j],dp[1][i1][k]3(jk)4);
    • 如果k=j1,同样的道理可得:
      dp[0][i][j]=max(dp[0][i][j],dp[0][i1][k]);//
      dp[0][i][j]=max(dp[0][i][j],dp[1][i1][k]3(jk)4);//jk=1,1

      对于dp[1][i][j],也就是恰好ij之前。同样的道理考虑状态转移。
      对于第i1个和第j个匹配或者插入在第j个之前的情况也是需要考虑的。
dp[0][i][j] = max(dp[0][i][j], dp[1][i - 1][j]);if(ss[i] == s[j]) dp[0][i][j] += 8;else dp[0][i][j] -= 5;if(i > 1) dp[1][i][j] = max(dp[1][i][j], dp[1][i - 1][j] - 3);

最后扫一下第二个字符串的最后一个字母在第一个字符串中的匹配位置,结果取最右。别忘了第二字符串的最后一个字母可以看成插入在第一个字符串的最后一个字母后面的情况。

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <climits>#include <cmath>#include <ctime>#include <cassert>#define IOS ios_base::sync_with_stdio(0); cin.tie(0);using namespace std;typedef long long ll;const int MAX_N = 110;int T;char s[MAX_N], ss[MAX_N];int dp[2][MAX_N][MAX_N];int main(){    scanf("%d", &T);    while(T--) {        scanf("%s%s", s + 1, ss + 1);        int len1 = strlen(s + 1) + 1, len2 = strlen(ss + 1) + 1;        if(len1 == len2 && len1 == 2) {            if(s[1] == ss[1]) printf("8\n");            else printf("-5\n");            continue;        }        memset(dp, 0, sizeof(dp));        for(int i = 1; i < len2; ++i) {            if( i > 1) dp[0][i][1] = -3 * (i - 1) - 4;            if(ss[i] == s[1]) dp[0][i][1] += 8;            else dp[0][i][1] -= 5;            dp[1][i][1] = -i * 3 - 4;            dp[0][i][0] = dp[1][i][0] = INT_MIN / 2;            for(int j = 2; j < len1 + 1; ++j) {                dp[0][i][j] = dp[1][i][j] = INT_MIN;                for(int k = 0; k < j; ++k) {                    if(k < j - 1) dp[0][i][j] = max(dp[0][i][j], dp[0][i - 1][k] - 3 * (j - k - 1) - 4);                    else dp[0][i][j] = max(dp[0][i][j], dp[0][i - 1][k]);                    dp[0][i][j] = max(dp[0][i][j], dp[1][i - 1][k] - 3 * (j - k) - 4);                    if(k < j - 1) dp[1][i][j] = max(dp[1][i][j], dp[0][i - 1][k] - 3 * (j - k - 1) - 11);                    else dp[1][i][j] = max(dp[1][i][j], dp[0][i - 1][k] - 7);                    dp[1][i][j] = max(dp[1][i][j], dp[1][i - 1][k] - 3 * (j - k) - 11);                }                dp[0][i][j] = max(dp[0][i][j], dp[1][i - 1][j]);                if(ss[i] == s[j]) dp[0][i][j] += 8;                else dp[0][i][j] -= 5;                if(i > 1) dp[1][i][j] = max(dp[1][i][j], dp[1][i - 1][j] - 3);            }        }        int ans = INT_MIN, n = len2 - 1;        for(int i = 1; i < len1; ++i) {            ans = max(ans, dp[0][n][i]);            ans = max(ans, dp[1][n][i]);        }        ans = max(ans, dp[1][n][len1]);        printf("%d\n", ans);    }    return 0;}
0 0
原创粉丝点击