题解报告:poj 2955 Brackets(括号匹配)

Description

We give the following inductive definition of a “regular brackets” sequence:

  • the empty sequence is a regular brackets sequence,
  • if s is a regular brackets sequence, then (s) and [s] are regular brackets sequences, and
  • if a and b are regular brackets sequences, then ab is a regular brackets sequence.
  • no other sequence is a regular brackets sequence

For instance, all of the following character sequences are regular brackets sequences:

(), [], (()), ()[], ()[()]

while the following character sequences are not:

(, ], )(, ([)], ([(]

Given a brackets sequence of characters a1a2 … an, your goal is to find the length of the longest regular brackets sequence that is a subsequence of s. That is, you wish to find the largest m such that for indices i1i2, …, im where 1 ≤ i1 < i2 < … < im ≤ nai1ai2 … aim is a regular brackets sequence.

Given the initial sequence ([([]])], the longest regular brackets subsequence is [([])].

Input

The input test file will contain multiple test cases. Each input test case consists of a single line containing only the characters ()[, and ]; each input test will have length between 1 and 100, inclusive. The end-of-file is marked by a line containing the word “end” and should not be processed.

Output

For each input case, the program should print the length of the longest possible regular brackets subsequence on a single line.

Sample Input

((()))
()()()
([]])
)[)(
([][][)
end

Sample Output

6
6
4
0
6
解题思路:经典区间dp,要求找出能配对的括号的最大个数。定义dp[i][j]表示第i到第j个括号的最大匹配数目,那么当第i个括号与第j个括号配对时,dp[i][j]为小的区间最大匹配数加上2即dp[i][j]=dp[i+1][j-1]+2,然后枚举区间[i,j]之间的断点k,合并更新区间[i,j]的最值,最终的答案就是dp[1][length]。时间复杂度为O(n^3)。
AC代码(32ms):
 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<string.h>
using namespace std;
const int maxn=;
char str[maxn];int length,dp[maxn][maxn];
bool check(char ch1,char ch2){
return (ch1=='('&&ch2==')')||(ch1=='['&&ch2==']');
}
int main(){
while(~scanf("%s",str+)&&strcmp(str+,"end")){
memset(dp,,sizeof(dp));length=strlen(str+);
for(int len=;len<=length;++len){//枚举区间长度1~length
for(int i=;i<=length-len;++i){//区间起点i
int j=i+len;//区间终点j
if(check(str[i],str[j]))dp[i][j]=dp[i+][j-]+;
for(int k=i;k<j;++k)//区间最值合并
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+][j]);
}
}
printf("%d\n",dp[][length]);
}
return ;
}

题解报告:NYOJ #15 括号匹配(二)

描述

给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来。
如:
[]是匹配的
([])[]是匹配的
((]是不匹配的
([)]是不匹配的

输入

第一行输入一个正整数N,表示测试数据组数(N<=10)
每组测试数据都只有一行,是一个字符串S,S中只包含以上所说的四种字符,S的长度不超过100

输出

对于每组测试数据都输出一个正整数,表示最少需要添加的括号的数量。每组测试输出占一行

样例输入

4
[]
([])[]
((]
([)]

样例输出

0
0
3
2
解题思路:上一道题的变形,同样求出给定括号的最大匹配数,那么最少还需要添加的括号数为length-dp[1][length]。
AC代码一(16ms):
 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<string.h>
using namespace std;
const int maxn=;
char str[maxn];int t,length,dp[maxn][maxn];
bool check(char ch1,char ch2){
return (ch1=='('&&ch2==')')||(ch1=='['&&ch2==']');
}
int main(){
while(~scanf("%d",&t)){
while(t--){
scanf("%s",str+);
memset(dp,,sizeof(dp));length=strlen(str+);
for(int len=;len<=length;++len){//区间长度
for(int i=;i<=length-len;++i){//区间起点i
int j=i+len;//区间终点j
if(check(str[i],str[j]))dp[i][j]=dp[i+][j-]+;
for(int k=i;k<j;++k)//更新区间最值
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+][j]);
}
}
printf("%d\n",length-dp[][length]);
}
}
return ;
}

AC代码二(16ms):记忆化搜索。定义dp[i][j]为第i个到第j个括号间至少需要增加的括号数,那么当区间[i,j]为空(i>j)即不含括号时,dp[i][j]=0;当区间只含一个字符即i==j时,dp[i][j]=1,表示至少需要增加1个括号;当第i个括号与第j个括号配对时,dp[i][j]为上一个状态子区间[i+1,j-1]中至少需要增加的括号数即dp[i+1][j-1];然后枚举[i,j]中的断点k,依次合并更新区间[i,j]值dp[i][j],表示从第i个字符到第k个字符至少需要增加的括号数加上从第k+1个字符到第j个字符至少需要增加的括号数,在这所有的k中取最小值作为dp[i][j]即可。

 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<string.h>
using namespace std;
const int maxn=;
const int inf=0x7fffffff;
char str[maxn];int t,length,dp[maxn][maxn];
bool check(char ch1,char ch2){
return (ch1=='('&&ch2==')')||(ch1=='['&&ch2==']');
}
int dfs(int x,int y){
if(x>y)return ;
else if(dp[x][y]>=)return dp[x][y];//表示已搜索过了,此时直接返回当前区间[x,y]的值
else if(x==y)return dp[x][y]=;//单个字符时,需要增加的括号数为1
else{
int var=inf;//先初始化为无穷大
if(check(str[x],str[y]))var=dfs(x+,y-);//如果能匹配,至少需要增加的括号数为上一个状态的值dp[x+1][y-1]
for(int k=x;k<y;++k)
var=min(var,dfs(x,k)+dfs(k+,y));//再更新当前区间[x,y]最少需要增加的括号数,由其子状态得来
return dp[x][y]=var;//返回并且赋值
}
}
int main(){
while(~scanf("%d",&t)){
while(t--){
scanf("%s",str+);memset(dp,-,sizeof(dp));
length=strlen(str+);
printf("%d\n",dfs(,length));
}
}
return ;
}

题解报告:NYOJ #746 整数划分(四)

描述

暑假来了,hrdv 又要留学校在参加ACM集训了,集训的生活非常Happy(ps:你懂得),可是他最近遇到了一个难题,让他百思不得其解,他非常郁闷。。亲爱的你能帮帮他吗?

问题是我们经常见到的整数划分,给出两个整数 n , m ,要求在 n 中加入m - 1 个乘号,将n分成m段,求出这m段的最大乘积

输入

第一行是一个整数T,表示有T组测试数据
接下来T行,每行有两个正整数 n,m ( 1<= n < 10^19, 0 < m <= n的位数);

输出

输出每组测试样例结果为一个整数占一行

样例输入

2
111 2
1111 2

样例输出

11
121
解题思路:定义dp[i][j]表示前i位插入j个乘号(i>j)能得到的最大乘积。根据区间dp思想我们可以从插入较少乘号的结果算出插入较多乘号的结果,即由子问题计算推出大问题。状态转移的关键点是,当插入第j个乘号时,需要枚举其放的位置j~i-1中哪个位置能产生最大的乘积值,则方程可表示为dp[i][j]=max(dp[i][j],dp[k][j-1]*num[k+1][i]),表示前k位中插入j-1(k>j-1)个乘号的最大值乘以从第k+1位到i位组成的数,取所有k中得到的最大乘积值作为dp[i][j],最终的答案就是dp[len][m-1]。
AC代码(4ms):
 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<string.h>
using namespace std;
typedef long long LL;
const int maxn=;
int t,len;LL m;char str[maxn];LL dp[maxn][maxn],num[maxn][maxn];
int main(){
while(cin>>t){
while(t--){
cin>>(str+)>>m;len=strlen(str+);memset(dp,,sizeof(dp));memset(num,,sizeof(num));
for(int i=;i<=len;++i){
num[i][i]=str[i]-'';//num[i,i]的值为其本身
for(int j=i+;j<=len;++j)//num[i][j]表示区间[i,j]组成对应的数
num[i][j]=num[i][j-]*+(str[j]-'');
dp[i][]=num[][i];//前i位插入0个乘号,其值为1~i对应的数即num[1][i]
}
for(int j=;j<m;++j)//插入j个乘号
for(int i=j+;i<=len;++i)//则最少有j+1位,枚举j+1~len位,此时插入j个乘号
for(int k=j;k<i;++k)//枚举j~i-1中的分断点k,找出最大的乘积作为dp[i][j]的值,即前i位加入j个乘号所能得到的最大乘积
dp[i][j]=max(dp[i][j],dp[k][j-]*num[k+][i]);
cout<<dp[len][m-]<<endl;//表示前len位插入m-1个乘号
}
}
return ;
}

区间dp实战练习的更多相关文章

  1. 【BZOJ-4380】Myjnie 区间DP

    4380: [POI2015]Myjnie Time Limit: 40 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 162  Solved: ...

  2. 【POJ-1390】Blocks 区间DP

    Blocks Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5252   Accepted: 2165 Descriptio ...

  3. 区间DP LightOJ 1422 Halloween Costumes

    http://lightoj.com/volume_showproblem.php?problem=1422 做的第一道区间DP的题目,试水. 参考解题报告: http://www.cnblogs.c ...

  4. BZOJ1055: [HAOI2008]玩具取名[区间DP]

    1055: [HAOI2008]玩具取名 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1588  Solved: 925[Submit][Statu ...

  5. poj2955 Brackets (区间dp)

    题目链接:http://poj.org/problem?id=2955 题意:给定字符串 求括号匹配最多时的子串长度. 区间dp,状态转移方程: dp[i][j]=max ( dp[i][j] , 2 ...

  6. HDU5900 QSC and Master(区间DP + 最小费用最大流)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5900 Description Every school has some legends, ...

  7. BZOJ 1260&UVa 4394 区间DP

    题意: 给一段字符串成段染色,问染成目标串最少次数. SOL: 区间DP... DP[i][j]表示从i染到j最小代价 转移:dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k ...

  8. 区间dp总结篇

    前言:这两天没有写什么题目,把前两周做的有些意思的背包题和最长递增.公共子序列写了个总结.反过去写总结,总能让自己有一番收获......就区间dp来说,一开始我完全不明白它是怎么应用的,甚至于看解题报 ...

  9. Uva 10891 经典博弈区间DP

    经典博弈区间DP 题目链接:https://uva.onlinejudge.org/external/108/p10891.pdf 题意: 给定n个数字,A和B可以从这串数字的两端任意选数字,一次只能 ...

随机推荐

  1. 【php】读取&quot;文件列表&quot;按时间倒序显示,并递归显示各层文件夹、!

    思路: 1.读取该php所在文件夹的文件列表,用"改动时间.文件名称"做键值对,塞入数组.对"改动时间"倒序.(貌似不能直接按时间倒序读取文件列表,此处为间接方 ...

  2. Codeforces Round #422 (Div. 2) A. I'm bored with life 暴力

    A. I'm bored with life     Holidays have finished. Thanks to the help of the hacker Leha, Noora mana ...

  3. app发布流程

    在app上架之前做两件事(instruments,profile): 1.代码静态分析:不用运行程序,直接检测代码有没有潜在的一些内存泄漏 2.动态分析:a l loctions/leaks 内存溢出 ...

  4. TButton.Repaint的执行过程

    测试,在按钮事件里写上 Button1.Repaint;(包括TWinControl.Invalidate;和procedure TWinControl.Update;两个函数,会被TButton所继 ...

  5. (31)java web的hibernate使用-一级缓存,二级缓存

    参考:https://blog.csdn.net/miachen520/article/details/52195832 hibernate自带一级缓存 和 二级缓存 一,一级缓存: 基于Sessio ...

  6. 使用std::mutex取代QMutex

    为了保证对某个资源的操作是原子性的(对资源读写时,只有当前的操作结束,才允许另外线程对其操作,这里有个理解误区,资源操作原子性不是说,当前某个线程获得了某个资源使用权,然后线程执行时间完毕,要切换线程 ...

  7. 大整数分解质因数(Pollard rho算法)

    #include <iostream> #include <cstring> #include <cstdlib> #include <stdio.h> ...

  8. JavaScript数组遍历:for、foreach、for in、for of、$.each、$().each的区别

    一.for Javascript中的for循环,它用来遍历数组 var arr = [1,2,3,4] for(var i = 0 ; i< arr.length ; i++){ console ...

  9. 总结 <stdlib.h>头文件 在算法中可能会用到的一些函数

    头文件<stdlib.>具有一定的总结性. 它定义了类型.宏和各种函数,这些函数用于:内存管理.排序和查找.整形运算.字符串到数字的转换.伪随机数序列.与环境的接口.把多字节字符串和字符转 ...

  10. Python之如果添加扩展包

    1.首先下载好你需要的扩展包 下载地址是http://www.lfd.uci.edu/~gohlke/pythonlibs/ 2.将你下载好的.whl文件放在你的python文件夹中的Lib\site ...