Light OJ 1025 - The Specials Menu(动态规划-区间dp)

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

题目大意:一串字符, 通过删除其中一些字符, 能够使这串字符变成回文串。 现在给你一串字符,问能够得到多少种不同的回文串;

注意:字符串"abba", 可以得到9串回文串,分别为'a', 'a', 'b', 'b', 'aa', 'bb', 'aba', 'aba', 'abba'.

解题思路:声明dp[i][j]为字符串[i,j]区间中通过删除可以得到不同回文串的数量

那么有以下两种情况:

1:当str[i] != str[j]时, dp[i][j] = dp[i][j-1] + dp[i+1][j] - dp[i+1][j-1]; (之所以减去dp[i+1][j-1] 是前面两项多加了一个dp[i+1][j-1])

2:当str[i] == str[j]时, dp[i][j] = (dp[i][j-1] + dp[i+1][j] - dp[i+1][j-1]) + (dp[i+1][j-1] + 1);(前面一项是指str[i]和str[j]不对应时能够组成回文串的方案数,第二项是指str[i]和str[j]对应时能够组成回文串的方案数)

需要注意的不能第一项直接循环i, 第二项直接循环j, 那么求dp[i][j]时,dp[i+1][j] 可能还没求得正确的值。

dp数组代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int N = 103;
ll dp[N][N];
char str[N];
void solve(int cases)
{
    scanf("%s", str);
    int l = strlen(str);
    memset(dp, 0, sizeof(dp));
    for(int i=0; str[i]; ++ i)
        dp[i][i] = 1;
    for(int len=1; len<l; ++ len)
    {
        for(int i=0; i+len<l; ++ i)
        {
            int j=i+len;
            if(str[i] != str[j])
                dp[i][j] = dp[i][j-1] + dp[i+1][j] - dp[i+1][j-1];
            else
                dp[i][j] = dp[i][j-1] + dp[i+1][j] + 1;
        }
    }
    printf("Case %d: %lld\n", cases, dp[0][l-1]);
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int i=1; i<=T; ++ i)
        solve(i);
    return 0;
}
View Code

记忆化搜索代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int N = 103;
ll dp[N][N];
char str[N];

ll dfs(int l, int r)
{
    if(l == r)
        return dp[l][r] = 1;
    if(dp[l][r] != -1)
        return dp[l][r];
    if(l > r)
        return 0;

    ll ans;
    if(str[l] != str[r])
        ans = dfs(l, r-1) + dfs(l+1, r) - dfs(l+1, r-1);
    else
        ans = dfs(l, r-1) + dfs(l+1, r) + 1;

    return dp[l][r] = ans;
}

void solve(int cases)
{
    scanf("%s", str);
    int l = strlen(str);
    memset(dp, -1, sizeof(dp));
    printf("Case %d: %lld\n", cases, dfs(0,l-1));
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int i=1; i<=T; ++ i)
        solve(i);
    return 0;
}
View Code

 

posted @ 2016-09-15 18:43  aiterator  阅读(193)  评论(0编辑  收藏  举报