NYOJ 15 括号匹配(区间dp)

跟括号匹配(一)截然不同  二 不在考栈的应用了  这道题是一道区间dp 

这道题写了很久 自己没写出来 参考了网上超过15篇博客才算是略知一二

本文提供两种解法

方法一:

定义dp[i][j]  为从位置I到位置j所需要的括号数量  状态转移的过程是这样的  枚举I和j  或者长度 如果第I个点和第j个点匹配  那么 dp[i][j] 是不是应该等于min(dp[I][j], dp[I + 1][j - 1]) 呢

如果不匹配那么我们可以枚举I到j中间所有的点  尝试是否能松弛 其实是尝试能否减小dp[I][j]  类似于松弛的操作 对就是这样 值得注意的是边界问题 和 dp数组的初始化问题

单独的一个位置dp[i][I]应该初始化为多少呢 没错 初始化为1 需要一个额外的括号使之匹配  差不多这样 


#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 105;
const int inf = 0x3f3f3f3f;
int main()
{
    int t, dp[maxn][maxn];
    char str[maxn];
    cin >> t ;
    while ( t -- ) {
        cin >> str ;
        int length = strlen(str);
        for (int i = 0; i < length; i ++) {
            for (int j = 0; j < length ; j ++) {
                if(i < j) dp[i][j] = inf;
                else if (i == j)dp[i][j] = 1;
                else dp[i][j] = 0;
            }
        }//len 不从0开始是因为枚举长度为0没有意义
        for (int len = 1; len < length; len ++) {//len表示从i开始的一段长度为len的区间
            for (int i = 0; i < length - len; i ++) {//i表示区间的起点
                int j = len + i;//j表示区间的终止点
                if(str[i] == '(' && str[j] == ')' || str[i] == '[' && str[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]);
            }
        }
        cout << dp[0][length - 1] << endl;
    }
}


方法二 :如果我们能找到这一串括号中的最大匹配量 那么需要额外添加的括号就是长度减去最大匹配量

稍微更改下方法一的代码就能得到方法二的代码  建议先看懂方法一在看方法二

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 105;
const int inf = 0x3f3f3f3f;
int main()
{
    int t, dp[maxn][maxn];
    char str[maxn];
    cin >> t ;
    while ( t -- ) {
        cin >> str ;
        int length = strlen(str);
        memset(dp , 0, sizeof(dp));
        for (int len = 1; len < length ; len ++) {//len依旧枚举长度
            for (int i = 0; i < length - len; i ++) {//i为起点
                int j = len + i;//终点
                if(str[i] == '(' && str[j] == ')' || str[i] == '[' && str[j] == ']')
                    dp[i][j] = dp[i + 1][j - 1] + 2;//如果匹配 那么当前区间的值肯定是一个较小的区间的值+2来的
                for (int k = i; k < j; k ++)//松弛过程
                    dp[i][j] = max(dp[i][j] , dp[i][k] + dp[k + 1][j]);
            }
        }
        cout << length - dp[0][length - 1] << endl;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值