读取括号

题目链接https://www.starrycoding.com/problem/423

动态规划解法
题意可以简化为将这一串括号从前往后分成合法括号组 求最小的组数
此题等价于最长括号匹配
设f[i]:从i位置开始的最长合法括号匹配长度

当前后括号匹配时,即
s[i] == '(' && s[i + f[i + 1] + 1] == ')'

有转移方程
f[i] = f[i + 1] + 2 + f[f[i + 1] + i + 2]

这样写有点难看 可以写成
f[i] = f[i + 1] + 2, f[i] += f[i + f[i]]

可以理解为两括号匹配,最大长度增加2
同时还要合并在f[i] + i之后的合法括号组的长度

求出f[i]后,再求一次dp
设dp[i]:从i位置开始到末尾最少可以分成多少组

有转移方程
dp[i] = dp[i + max(f[i] + 1)] + 1

代码如下

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

using i64 = long long;

int main () {
    ios::sync_with_stdio(0), cin.tie(0);
    int n;cin >> n;
    string s;cin >> s;
    s = " " + s;
    vector<int> S;
    // f[i]:从i位置开始能读取的最多合法括号序列
    vector<int> f(n + 2);
    for (int i = n;i >= 1; -- i) {
        if (s[i] == ')') ;
        else {
            if (s[i] == '(' && s[i + f[i + 1] + 1] == ')') {
                f[i] = f[i + 1] + 2;
                f[i] += f[i + f[i]];
            }
        }
    }
    // dp[i]:从i位置读取到末尾需要的次数
    vector<int> dp(n + 2);
    for (int i = n;i >= 1; -- i) {
        dp[i] = dp[i + max(f[i], 1)] + 1;
    }
    cout << dp[1] << '\n';
   
    return 0;
}
posted @ 2025-05-19 15:15  _ryuuko  阅读(16)  评论(1)    收藏  举报