括号配对计数

原题

思路

经典的区间dp. 显然 \(dp[i][j]\) 表示将字符串的 \([i, j]\) 区间变合法的最少操作数.
\(i, j\) 没有配对时有:
\(dp[i][j] = \mathop{min\{dp[i][k] + dp[k + 1][j]\}}\limits_{i \leq k < j}\)

\(i, j\) 配对时有:
\(dp[i][j] = \mathop{min\{dp[i + 1][j - 1], min\{dp[i][k] + dp[k + 1][j]\}\}}\limits_{i \leq k < j}\)

注意初始时 \(dp[i][i] = 1(1 \leq i \leq n)\) 就好了.

代码

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

inline int read() {
    int x = 0; char c = getchar(); bool f = 1;
    while(c < '0' || c > '9') { if(c == '-') f = 0; c = getchar(); }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return (f ? x : -x);
}

const int N = 1e3 + 10, INF = 0x3f3f3f3f;
int n, dp[N][N];
char s[N];

int main() {
    cin >> (s + 1);
    n = strlen(s + 1);

    for(int i = 1; i <= n; ++i) dp[i][i] = 1;

    for(int l = 1; l < n; ++l) {
        for(int i = 1; i <= n; ++i) {
            int j = i + l;
            dp[i][j] = INF;
            
            if(s[i] == '(' && s[j] == ')' || s[i] == '[' && s[j] == ']') 
                dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
            
            for(int k = i; k < j; ++k)
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
        }
    }

    printf("%d\n", dp[1][n]);

    return 0;
}
posted @ 2022-05-16 14:58  聂天泽  阅读(44)  评论(0)    收藏  举报