NYOJ15|括号匹配(二)|区间DP|Elena

括号匹配(二)

时间限制:1000 ms  |  内存限制:65535 KB

难度:6

描述
   给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来。
如:
[]是匹配的
([])[]是匹配的
((]是不匹配的
([)]是不匹配的
输入
第一行输入一个正整数N,表示测试数据组数(N<=10)
每组测试数据都只有一行,是一个字符串S,S中只包含以上所说的四种字符,S的长度不超过100
输出
对于每组测试数据都输出一个正整数,表示最少需要添加的括号的数量。每组测试输出占一行
样例输入
4
[]
([])[]
((]
([)]
样例输出
0
0
3
2

对于这道题,我还是跟②2017=5.13-7.1中的合并石子一样,贴出两份不同的类型的题解以及解释。思路其实差不多,是枚举过程有些差异,分给两种不同习惯的人。DP[i][j]指i到j中合法括号配对数。比如对于字符串(),DP[1][2]=2。SP[]用于存储括号字符串,我是从下标1存储起的。N存储字符串的长度。我们可以这样想,DP[i][j]合法的情况只有以下三种:1.SP[i]==‘(‘&&SP[j]==‘)‘且DP[i+1][j-1]合法。2.SP[i]==‘[‘&&SP[j]==‘]‘且DP[i+1][j-1]合法。3.能够切成两段合法的括号序列。

我们可以计算出合法的括号配对数,然后用字符串长度减去它,就是答案。这里合法的括号配对数指:比如对于字符串(),DP[1][2]=2,则合法括号配对数指2。
第一种题解:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 using namespace std;
 6 int T,DP[101][101],N;
 7 char SP[101];
 8 int main()
 9 {
10     scanf("%d",&T);
11     while (T--) {
12         N=0;
13         scanf("%s",SP+1);
14         while (SP[N+1]) N++;
15         memset(DP,0,sizeof(DP));
16         for(int i=N-1; i>=1; i--)
17             for(int j=i+1; j<=N; j++) {
18                 if ((SP[i]==‘(‘&&SP[j]==‘)‘)||(SP[i]==‘[‘&&SP[j]==‘]‘))
19                     DP[i][j]=DP[i+1][j-1]+2;
20                 for (int k=i; k<j; k++)
21                     DP[i][j]=max(DP[i][j],DP[i][k]+DP[k+1][j]);
22             }
23         printf("%d\n",N-DP[1][N]);
24     }
25     return 0;
26 }

code1

我仍然挑出部分代码讲解:

memset(DP,0,sizeof(DP));//因为有T组数据,所以对于每一组数据我们都需要初始化DP数组。
for(int i=N-1; i>=1; i--)
  for(int j=i+1; j<=N; j++) {
    if ((SP[i]==‘(‘&&SP[j]==‘)‘)||(SP[i]==‘[‘&&SP[j]==‘]‘))//第1、2种合法情况的判断。
      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]);//对于第三种情况的判断。
  }
printf("%d\n",N-DP[1][N]);

肯定有人要问:为什么DP[i][j]=max(DP[i][j],DP[i][k]+DP[k+1][j]);就可以计算出如([])()这样的情况的答案呢?

是这样的,我们可以这么想:假如k枚举到了3,那么DP[1][3]就是2,DP[4][6]也是2,DP[1][6]答案就是4。

假如k枚举到了4,那么DP[1][4]答案就是4,DP[5][6]答案就是2,DP[1][6]的答案就是6,大于原来的答案且合法,于是更新。

这样就可以完美地从括号中间分割出来啦~因为如果()()是类似这样的合法括号序列,从中间分割出来的答案一定是最优的,所以就可以保证答案的正确性啦!

这种写法的原理是:当i相同时,j小的先算;当i不相同时,i大的先算。

比如:DP[i][k]比DP[i][j]先算,因为i=i,k比较小;DP[k+1][j]比DP[i][j]先算,因为k+1不等于i,k+1>i。

这样就可以保证循环先后的正确性,也就是保证我们计算这一步需要用的东西在计算这一步之前就计算好了。

第二种写法:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 using namespace std;
 6 int T,DP[101][101],N;
 7 char SP[101];
 8 int main()
 9 {
10     scanf("%d",&T);
11     while (T--) {
12         N=0;
13         scanf("%s",SP+1);
14         while (SP[N+1]) N++;
15         memset(DP,0,sizeof(DP));
16         for (int LEN=2; LEN<=N; LEN++)
17         for (int i=1,j=LEN; j<=N; i++,j++) {
18             if ((SP[i]==‘(‘ && SP[j]==‘)‘)||(SP[i]==‘[‘&&SP[j]==‘]‘))
19                 DP[i][j]=DP[i+1][j-1]+2;
20             for (int k=i; k<j; k++)
21                 DP[i][j]=max(DP[i][k]+DP[k+1][j],DP[i][j]);
22         }
23         printf("%d\n",N-DP[1][N]);
24     }
25     return 0;
26 }

code2

这种写法其实本质上和第一种是一样的,只是枚举的方式略有不同,是通过枚举序列长度来保证DP循环的先后性的,所以放出来给熟悉这种写法的人看。


memset(DP,0,sizeof(DP));//初始化
for (int LEN=2; LEN<=N; LEN++) //枚举序列长度
  for (int i=1,j=LEN; j<=N; i++,j++) {
    if ((SP[i]==‘(‘ && SP[j]==‘)‘)||(SP[i]==‘[‘&&SP[j]==‘]‘))//第1、2种合法情况的判断。
      DP[i][j]=DP[i+1][j-1]+2;//括号有两边,所以+2;
    for (int k=i; k<j; k++)
      DP[i][j]=max(DP[i][k]+DP[k+1][j],DP[i][j]);//对于第三种情况的判断。
  }
printf("%d\n",N-DP[1][N]);

对于第三种情况的判断上面讲的很清楚了。

有问题可以直接在评论里面提问,有需要转载的请得到我的允许,否则按侵权处理。


Elena loves NiroBC forever!

时间: 2024-12-13 17:04:38

NYOJ15|括号匹配(二)|区间DP|Elena的相关文章

括号匹配问题 区间DP经典问题

题目链接 http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=15 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来.如:[]是匹配的([])[]是匹配的((]是不匹配的([)]是不匹配的 分析:要求要添加多少个,可以求出最大匹配的长度,这样剩下的都是没有匹配的,所以每个对于一个匹配就可以了. 即 答案 =

poj2955:括号匹配,区间dp

题目大意: 给一个由,(,),[,]组成的字符串,其中(),[]可以匹配,求最大匹配数 题解:区间dp: dp[i][j]表示区间 [i,j]中的最大匹配数 初始状态 dp[i][i+1]=(i,i+1可以匹配)?2:0 状态转移见代码 代码: #include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #includ

NYOJ15-括号匹配(二)-区间DP

http://acm.nyist.net/JudgeOnline/problem.php? pid=15 dp[i][j]表示从i到j至少须要加入多少个括号才干满足匹配条件. 初始化: if(i == j) dp[i][j] = 1; else dp[i][j] = INF; 状态转移: 当i < j时; if(match(str[i], str[j])) dp[i][j] = min(dp[i][j], d[i + 1][j - 1]); 然后切割区间, 找最优切割点k. (i <= k &

NYOJ15括号匹配

NYOJ15括号匹配 括号匹配(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:6 描述 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来.如:[]是匹配的([])[]是匹配的((]是不匹配的([)]是不匹配的 输入 第一行输入一个正整数N,表示测试数据组数(N<=10)每组测试数据都只有一行,是一个字符串S,S中只包含以上所说

「kuangbin带你飞」专题二十二 区间DP

layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - kuangbin - 区间DP - 动态规划 传送门 B.LightOJ - 1422 Halloween Costumes 题意 按顺序参加舞会,参加一个舞会要穿一种衣服,可以在参加完一个舞会后套上另一个衣服再去参加舞会,也可以在参加一个舞会的时候把外面的衣服脱了,脱到合适的衣服,但是脱掉的衣服不能再穿,参加完

【栈思想、DP】NYOJ-15 括号匹配(二)

括号匹配(二) 描述 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来.如:[]是匹配的([])[]是匹配的((]是不匹配的([)]是不匹配的 输入 第一行输入一个正整数N,表示测试数据组数(N<=10)每组测试数据都只有一行,是一个字符串S,S中只包含以上所说的四种字符,S的长度不超过100 输出 对于每组测试数据都输出一个正整数,表示最少需要添加的括

NYOJ15 括号匹配(二)

经典的动态规划题 这道题感觉确实有一定难度,感觉自己的dp学的弱爆了!以后还要努力啊! 括号匹配(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:6 描述 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来.如:[]是匹配的([])[]是匹配的((]是不匹配的([)]是不匹配的 输入 第一行输入一个正整数N,表示测试数据组数(N<

imooc数据结构探险-栈篇 栈应用括号匹配二 由群友启发改良james_yuan老师算法

如图所示 引用群友内容 //老师代码有点麻烦了,不用声明两个mystack的,直接判断是否是左括号, //是的话就在mystack中push另一半括号:如果是右括号且又不是需要的括号, //就直接打印不匹配,如果是需要的右括号,就pop掉左括号.最后看mystack中栈顶是否为0,为0则打印括号匹配 /* 老师最后一点其实错了,default 其实没有必要写,只要把pNeedStack->pop(currentNeed)改为 if(!pNeedStack->pop(currentNeed))

NYOJ 15 括号匹配(二) dp

题目连接:check here~ 题意是说给一个字符串,包含'(',')','[',']'四种字符,判断至少需要添加几个字符使所给字符串括号匹配. 区间型动态规划,设dp[i][j]表示在字符串s中i位置到j位置所需要添加的最少的字符(i <= j) 有两种情况: 1.dp[i][j] = dp[i+1][j] + 1; 表示:在i到j之间没有与s[i]相匹配的括号,则必须添加一个字符来与之匹配,问题就转化为:从i+1位置到j位置所需要添加的最少的字符+1. 2.dp[i][j] = min{