NKOI 1507 做错的括号

【NK月赛 JUNE2012 E】做错的作业

Time Limit:10000MS  Memory Limit:65536K
Total Submit:94 Accepted:54 
Case Time Limit:1000MS

Description

小影(人名) 的数学作业错误百出. 
老师:“你作业的表达式里面只有n个括号,怎么就写错了这么多?” 
“n那么大,都到300了。” 
老师:“那第一个小题只有一个括号你都写错了,这怎么解释?你看,你就写了一个‘(’,明显漏掉了一个‘)’吧?” 
“这……”小影似乎很清楚的记得自己是写的“()”,可是现在怎么只剩下“(”了呢? 
老师:“你看别人某某,写的多好?十道题都做对了。这样吧,我不看你的计算结果了,只看你的括号匹配得正不正确,你今天之内把你的括号修改正确就可以了……” 
“嘿嘿……我把括号全部划掉不就全对了?”小影阴险地想。 
老师:“……不过有一个条件:你只能添加括号而不能把括号划掉,并且你只能添加最少数量的括号。” 
“天呐!”小影瘫倒了,要知道十个题目里面只有第一题很简单,其他的题目括号数目是巨多的。 
看来,只能请善良的你帮帮小影了。

Input

只有一行,为一个长度为n的字符串,代表小影作业中写的括号。其中有4类括号“()”“[]”“<>”“{}”,“(”和“)”匹配,“[”和“]”匹配,“<”和“>”匹配,“{”和“}”匹配,左括号必须在左,右括号必须在右,其他组合是不匹配的。两个匹配的括号中间可以夹有其他已经匹配的括号。如“([<{}>])(){}”就是匹配的。

Output

一个整数,为小影最少需要添加的括号数目。

Sample Input

([(]{})(<>))

Sample Output

2

Hint

对于30%的数据,n<=50; 
对于100%的数据,n<=300

Source

命题:Chyy(08级24班);审题:Cauchy(08级5班);数据:Chyy。


我们用f[i][j]表示从第i个点开始的j个位置匹配所需的最小括号数

尝试求如下括号序列的最优解
   1  2  3  4  5  6  7
   (   [  (   ]  {  }   )
讨论j=1
f[1][1]=1   f[2][1]=1   f[3][1]=1   f[4][1]=1   f[5][1]=1   f[6][1]=1   f[7][1]=1
讨论j=2   
f[1][2]=2   f[2][2]=2   f[3][2]=2   f[4][2]=2   f[5][2]=0   f[6][2]=2
//新增的括号如果在前面j-1个括号中未找到匹配的,则在+1, 比如f[6][2]=f[6][1]上+1)
讨论j=3
f[1][3]=f[1][2]+1=3   //第3个括号在前两个括号中找不到匹配的
f[2][3]=f[3][1]=1       // (2和4匹配,在他们之间只有f[3][1])
f[3][3]=3  
f[4][3]=f[4][1]=1       //5和6已匹配
f[5][3]=f[5][2]+1       //第7个括号在前两个括号中没找到匹配的                
讨论j=4
f[1][4]=f[1][1]+f[3][1]=2   //(2和4已匹配)
f[2][4]=f[2][3]+1=2           //第5个括号在前三个括号中没有找到匹配的      
f[3][4]=f[3][2]=2;               //(5和6已匹配)
f[4][4]=f[4][3]+1=2;          //第7个括号在前三个括号中没有找到匹配的
讨论j=5 
f[1][5]=f[1][4]+1; 
f[2][5]=f[2][3]=1; 
f[3][5]=f[4][3]=1
讨论j=6
f[1][6]=f[1][4]=2  
f[2][6]=f[2][1]+f[4][3]=2
讨论j=7
f[1][7]=f[2][1]+f[4][3] 或f[2][5]   ,选f[2][5]=1
因此我们可以推出状态转移方程f[i][j]=min{f[i][j-1]+1, min{f[i][k-1]+f[k+i][j-k-1]}  }

其中min{f[i][k-1]+f[k+i][j-k-1]} 是表示i后第j个括号和i后第k个括号匹配,1=<k<=j-1

为了方便讨论,我们在输入的时候应该将输入的括号换成数字,从而容易判断括号是否匹配

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int inf=2e9;
char c[305];
int n,f[305][305],s[305];
int main(){
	scanf("%s",c+1);
	int i,j,k;
	n=strlen(c+1);
	for(i=1;i<=n;i++){
		if(c[i]=='(')s[i]=1;
		if(c[i]==')')s[i]=9;
		if(c[i]=='{')s[i]=2;
		if(c[i]=='}')s[i]=8;
		if(c[i]=='<')s[i]=3;
		if(c[i]=='>')s[i]=7;
		if(c[i]=='[')s[i]=4;
		if(c[i]==']')s[i]=6;
	}
	for(i=1;i<=n;i++)
	    for(j=1;j<=n;j++)
	        f[i][j]=inf;
	for(i=1;i<=n;i++)
	    f[i][1]=1;
	for(j=1;j<=n;j++)
	    for(i=1;i<=n-j+1;i++){
	    	f[i][j]=min(f[i][j],f[i][j-1]+1);
	    	for(k=1;k<=j-1;k++)
	    	    if(s[i+k-1]+s[i+j-1]==10&&s[i+k-1]<s[i+j-1])
	    	        f[i][j]=min(f[i][j],f[i][k-1]+f[k+i][j-k-1]);
		}
	cout<<f[1][n];
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值