cf607 B. Zuma(区间dp,回文串)


题意:

给定数组,每次可以删除一个回文子段,求最少几次可以删完。

\(1\le n \le 500\)

思路:

\(f(l,r)\) 表示删除 \([l,r]\) 需要的最小次数。如果 \(a_l=a_r\),那么 \(a_l\)\(a_r\) 可以接到 \([l+1,r-1]\) 中的某个回文序列中,不需要额外代价。

特殊处理长度为2的子段

const int N = 505;
int n, a[N], f[N][N];

main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];

    memset(f, INF, sizeof f);
    for(int i = 1; i <= n; i++) f[i][i] = 1;
    for(int i = 2; i <= n; i++) if(a[i] == a[i-1]) f[i-1][i] = 1;

    for(int len = 2; len <= n; len++)
        for(int l = 1; l + len - 1 <= n; l++)
        {
            int r = l + len - 1;
            if(a[l] == a[r]) f[l][r] = min(f[l][r], f[l+1][r-1]);
            for(int k = l; k < r; k++)
                f[l][r] = min(f[l][r], f[l][k] + f[k+1][r]);
        }

    cout << f[1][n];
}