51nod 回文串划分

哇很好的题..
发现在dp中,找到"转化的一步",枚举这一步非常重要.
这题首先是n2的处理出区间回文,一开始我一直想的是dp[i][j]来代表[i,j]之间最少划分几个,这个是容易的,但是会t,我想了几个优化,其中一个便是不是遍历i,j中间每一个点,而是直接选p,[i,p]为回文串,这样可以提高速度,但是仍然不够.我就想换一个状态.
dp[i],前i个最少划分几个,其实这个我很早有想到,但是不知道在利用前面的i时,中间那一段是处理不出来的,后来发现没有必要,只需要遍历从右端点往左的每一个回文串,就可以了.因为显然这样也可以"覆盖全部状态".

#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef long long LL;
const int MAXN = 5e3 + 17;
const int MOD = 1e9 + 7;
bool dp[MAXN][MAXN];
int dpx[MAXN];
vector<int> vec[MAXN];
int main(int argc, char const* argv[])
{
#ifdef noob
    freopen("Input.txt", "r", stdin);
    freopen("Output.txt", "w", stdout);
#endif
    string str;
    cin >> str;
    int n = str.length();
    for (int i = 0; i < n; ++i) {
        dp[i][i] = 1;
    }
    for (int i = 0; i < n - 1; ++i) {
        if (str[i] == str[i + 1])
            dp[i][i + 1] = 1;
    }
    for (int l = 3; l < n; ++l) {
        for (int i = 0; i + l - 1 < n; ++i) {
            int j = i + l - 1;
            if (str[i] == str[j])
                dp[i][j] = dp[i + 1][j - 1];
        }
    }
    for (int j = 0; j < n; ++j) {
        if (dp[0][j])
            dpx[j] = 1;
        else
            dpx[j] = 19990317;
    }

    for (int i = 0; i < n; ++i) {
        for (int j = i; j < n; ++j) {
            if (dp[i][j]) {
                vec[j].push_back(i);
            }
        }
    }
    for (int j = 0; j < n; ++j) {
        for (auto i : vec[j])
            dpx[j] = min(dpx[j], dpx[i - 1] + 1);
    }
    cout << dpx[n - 1] << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37802215/article/details/80263988
今日推荐