UVA 1625 Color Length DP

  题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4500

  题目描述: 两个字符串 ,组成一个新的字符串, 每次只能从其中一个的开头选一个加到新的尾, 问l(i)的最小值

  解题思路: dp(i, j)  表示从第一个字符串中取i 个, 第二个字符串中取j个时的最优方案, 我们创建数组c 表示从第一个字符串中取i 个, 第二个字符串中取j个时开始还没有结束的字符的数量, 这样状态转移方程就可以写成: dp(i,j) = min(dp(i-1,j)+c[i-1,j], dp(i, j-1)+c[i,j-1]) 我们每做一次状态转移就更新一次c数组

  代码: 

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <cstring>
#include <iterator>
#include <cmath>
#include <algorithm>
#include <stack>
#include <deque>
#include <map>

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
typedef long long LL;
using namespace std;
const int maxn = 5000+5;

int dp[maxn][maxn];  // dp(i,j) p中取i个, q中取j个的最小代价
char p[maxn];
char q[maxn];
int c[maxn][maxn]; // c(i,j) p中取i个, q中取j个已经开始还没有结束字符的个数
int sp[30], sq[30], ep[30], eq[30];
const int INF = 0x3fffffff;

int main() {
    int t;
    scanf( "%d", &t );
    while( t-- ) {
//        scanf( "%s", p+1);
//        scanf( "%s", q+1);
        scanf("%s%s", p + 1, q + 1);
        int n = (int)strlen(p+1);
        int m = (int)strlen(q+1);
        memset(c, 0, sizeof(c));
        memset(dp, 0, sizeof(dp));
        
        for( int i = 1; i <= n; i++ ) p[i] -= 65;
        for( int j = 1; j <= m; j++ ) q[j] -= 65;
        for( int i = 0; i < 26; i++ ) {
            sp[i] = sq[i] = INF;
            ep[i] = eq[i] = 0;
        }
        for( int i = 1; i <= n; i++ ) {
            sp[p[i]] = min( sp[p[i]], i );
            ep[p[i]] = i;
        }
        for( int i = 1; i <= m; i++ ) {
            sq[q[i]] = min( sq[q[i]], i );
            eq[q[i]] = i;
        }
        for( int i = 0; i <= n; i++ ) {
            for( int j = 0; j <= m; j++ ) {
                if( !i && !j ) continue;
                int v1, v2;
                v1 = v2 = INF;
                if( i ) v1 = dp[i-1][j] + c[i-1][j];
                if( j ) v2 = dp[i][j-1] + c[i][j-1];
                dp[i][j] = min( v1, v2 );
                if( i ) {
                    c[i][j] = c[i-1][j];
//                    if( sp[p[i]] == i && (ep[p[i]] > i || eq[p[i]] > j ) ) c[i][j]++;
//                    if( ep[p[i]] == i && eq[p[i]] <= j ) c[i][j]--;
                    if (sp[p[i]] == i && sq[p[i]] > j)  c[i][j]++;
                    if (ep[p[i]] == i && eq[p[i]] <= j) c[i][j]--;
                }
                else if( j ) {
                    c[i][j] = c[i][j-1];
//                    if( sq[q[j]] == j && (eq[q[j]] > j || ep[q[j]] > i ) ) c[i][j]++;
//                    if( eq[q[j]] == j && ep[q[j]] <= i ) c[i][j]--;
                    if (sq[q[j]] == j && sp[q[j]] > i)  c[i][j]++;
                    if (eq[q[j]] == j && ep[q[j]] <= i) c[i][j]--;
                }
            }
        }
        printf( "%d
", dp[n][m] );
    }
    return 0;
}
View Code

  思考:状态转移时, 要注意和状态转移有关的变量有哪几个, 是否能够从原条件中预处理出来, 如果能够预处理出来就去做, 否则就换状态

原文地址:https://www.cnblogs.com/FriskyPuppy/p/7323400.html