CodeForces 154A Hometask dp

题目链接:

http://codeforces.com/problemset/problem/154/A

题意:

给你一个字符串,和若干模板串(长度为2),至少删除多少个字母,使得字符串的字串里面没有模板串。

题解:

dp[i][j]表示合法子串s[0...i]的最后一位为j时的最小花费(花费指删除的字母个数)

对每一位考虑删和不删的情况:

如果删,那么它的最后一位一定为之前出现过的。

如果不删,那么s[i]就是最后一位。

考虑这两种情况的转移就可以了。

时间复杂度:O(n*26*26)

代码:

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

const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;

int dp[maxn][33];
int cnt[33];
bool mp[33][33];

char str[maxn];
int len, n;

void init() {
    memset(dp, 0x3f, sizeof(dp));
    memset(mp, 0, sizeof(mp));
    memset(cnt, -1, sizeof(cnt));
}

inline int f(char c) {
    return c - 'a' + 1;
}

int main() {
    while (scanf("%s%d", str, &n) == 2) {
        init();
        len = strlen(str);
        char s[11];
        for (int i = 0; i<n; i++) {
            scanf("%s", s);
            mp[f(s[0])][f(s[1])] = mp[f(s[1])][f(s[0])] = 1;
        }
        cnt[f(str[0])] = 0;
        dp[0][f(str[0])] = 0;
        for (int i = 0; i<len; i++) dp[i][0] = i + 1;
        for (int i = 1; i<len; i++) {
            int ch = f(str[i]);
            cnt[ch] = i;
            //第i位删
            for (int j = 1; j <= 26; j++) {
                if (cnt[j] != -1) {
                    int k = cnt[j];
                    dp[i][j] = min(dp[i][j], dp[k][j] + i - k);
                }
            }
            dp[i][ch] = min(dp[i][ch], dp[i - 1][0]);
            //第i位不删
            for (int k = 1; k <= 26; k++) {
                if (mp[k][ch] == 0) {
                    dp[i][ch] = min(dp[i][ch], dp[i - 1][k]);
                }
            }
        }
        int ans = INF;
        for (int i = 1; i <= 26; i++) {
            ans = min(ans, dp[len - 1][i]);
        }
        printf("%d
", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fenice/p/5460399.html