一、题目描述
测试输入 期待的输出 时间限制 内存限制 额外进程 测试用例 1 以文本方式显示
- 7↵
- )())↵
- )↵
- ((↵
- ((↵
- (↵
- )↵
- )↵
以文本方式显示
- 2↵
1秒 64M 0 测试用例 2 以文本方式显示
- 2↵
- (())↵
- ()↵
以文本方式显示
- 1↵
1秒 64M 0
二、题目分析
(Ⅰ)什么样的括号序列是有用的(可解的)?
比如说“((”可以和“))”搭配成为匹配的括号序列,称序列“((”和序列“))”均是有用的,或者说是“可解的”。但是像“)(”这样的序列,没有任何一个序列可以和它匹配,称“)(”就是“不可解的”。
(Ⅱ)怎么处理括号序列?
合法的括号序列指的是每一个左括号都有对应一个右括号,而且这个左括号应该在其对应的右括号的左边。
首先,我们来看,假定给你一段括号序列,你怎么判断它是“合法的”?
合法的括号序列例如:((()())()) == ( ( () () ) () )
不难知道,如果一段括号序列是“合法的”,它的一个必要条件是左括号的数量等于右括号的数量,而且进一步看,如果我们从左到右数起,左括号的数量一定恒是大于等于右括号的数量的。
(不妨想象一下,如果出现左括号的数量小于右括号,那么一定是非法的)
例如())(,虽然整体上看左括号的数量等于右括号的数量,但是从左往右看下去:
())(:一个左括号,零个右括号,1>0,没有问题。
())(:一个左括号,一个右括号,1=1,没有问题。
())(:一个左括号,两个右括号,1<2,出现了左括号数量小于右括号数量,此时就可以断定这个序列“非法”。
如何表达“大于等于”这个关键信息呢?
用我们小学二年级就学过的正负数哇。
我们约定左括号'('=+1,右括号')'=-1。
用这个方法,判断括号序列是否可解:
判断一个括号序列是可解的:如果一个括号序列从左向右计算的过程中恒大于等于0,或者从右向左计算的过程中恒小于等于0,那么这个序列是可解的。
判断一个括号序列是不可解的:如果一个括号序列在从左向右计算的过程中出现了负值,在从右向左计算的过程中又出现了正值,就说明这个括号序列是不可解的。
假设括号序列是“有解的”,那么用计算的方法还能帮助化简括号序列。
如果最终序列=0,那么该括号序列“合法”;
如果最终序列>0,那么该括号序列有多余的左括号;
如果最终序列<0,那么该括号序列有多余的右括号。
举例来说,现在给你的括号序列是这样的:()(
从左向右依次计算,()( <==> +1 -1 +1 = +1 <==> (
事实上,()(和(就是等价的。这种化简方法可以很方便地处理不同的括号序列。
(Ⅲ)满足什么条件的两个序列可以互相匹配?
两个可解的括号序列,如果它们的和为0,那么就是相互匹配的。
三、思路
代码分为五个部分,
①读入n行括号序列;
②化简n行括号序列;
③通过计算的方法判断括号序列是否可解;
④如果可解,那么计算这个括号序列的值;
⑤通过枚举的方法判断是否有可以相互匹配的序列。
以用例1为例,对七组序列处理成下述表格:
然后就可以一眼看出-2和2匹配,-1和1匹配,总共两组。
四、代码实现
首先引入函数
int valuate(char c) {
if ( c == '(' ) return 1;
else if ( c == ')' ) return -1;
}
//函数valuate的作用是将‘(’换算为1,将‘)’换算为-1
还需要
#include <stdio.h>
#include <string.h>
#include <math.h>
#define N 100010
long int solvable[N],value[N];
char brackets[N];
//solvable[i]只能为0或1,如果是0,表明第i组括号序列不可解;如果是1,表明第i组括号序列可解。
//value[i]是计算出来的括号序列的值。
//brackets临时存储读入的括号序列。
主函数main分为三部分:输入、化简并计算、判断匹配。
输入部分
int n,score=0;
scanf("%d",&n);
for (int i=0;i<n;i++) {
scanf("%s",&brackets);
在输入brackets的同时进行化简并计算的操作
for ( int i=0 ; i<n ; i++ ) {
scanf("%s",&brackets);
int len = strlen( brackets );
//初始时的value值为0,并且默认为合法。
value[i] = 0;
solvable[i] = 1; //solvable值为1表示合法
int partial_min = 0;
//计算括号序列的逐项值,并且记录该过程中出现的最小负值(如果有的话)
for ( int j=0 ; j<len ; j++ ) {
value[i] = value[i] + valuate( brackets[j] );
if ( value[i] < partial_min ) {
partial_min = value[i];
}
}
//如果计算过程中出现了负值,需要判断这是属于无解的情况还是属于全是右括号的情况。
if ( partial_min < 0 ) {
int partial_max = 0;
for ( int j = len-1 ; j>=0 ; j-- ) {
partial_max = partial_max + valuate( brackets[j] );
//如果从右向左逐项计算的过程中出现了正值,那么说明无解,将solvable置为0,0表示无解。
if ( partial_max > 0 ) {
solvable[i] = 0;
break;
}
}
}
然后接着判断是否匹配
首先定义M
int M = ( all_max + all_min ) > 0 ? all_max : (0-all_min) ;
all_max是所有value中最大的那一项正值,all_min是所有value中最小的那一项负值。
int count_positive , count_negative;
//count_positive记录正值的数量,count_negative记录负值的数量
for ( int i=0 ; i<=M ; i++) {
count_positive = 0 ;
count_negative = 0 ;
for ( int j=0 ; j<n ; j++ ) {
if ( solvable[j] == 1 && ( abs(value[j]) == i ) ) {
if ( value[j] >= 0 ) count_positive++;
else count_negative++;
}
}
if ( i == 0 ) score+= (count_positive/2);
else score+= ( (count_positive-count_negative)>0 ? count_negative:count_positive );
}
注意,我这里匹配方法效率低下,完全可以优化。不过就这道题目而言,足够AC了。
五、完整代码
#include <stdio.h>
#include <string.h>
#include <math.h>
#define N 100010
long int solvable[N],value[N];
char brackets[N];
int main() {
int valuate(char);
int n,score=0;
scanf("%d",&n);
int all_max=0,all_min=0;
for (int i=0;i<n;i++) {
scanf("%s",&brackets);
int len = strlen(brackets);
value[i]=0;
solvable[i]=1;
int partial_min = 0;
for (int j=0;j<len;j++) {
value[i] = value[i] + valuate(brackets[j]);
if ( value[i] < partial_min ) {
partial_min = value[i];
}
}
if (partial_min<0) {
int partial_max = 0;
for (int j=len-1;j>=0;j--) {
partial_max = partial_max + valuate(brackets[j]);
if (partial_max>0) {
solvable[i]=0;
break;
}
}
}
if (solvable[i]==1) {
if (value[i]<all_min) all_min=value[i];
if (value[i]>all_max) all_max=value[i];
}
}
int M = ( all_max + all_min ) > 0 ? all_max : (0-all_min) ;
int count_positive,count_negative;
for (int i=0;i<=M;i++) {
count_positive=0;
count_negative=0;
for (int j=0;j<n;j++) {
if (solvable[j]==1 && ( abs(value[j])==i) ) {
if (value[j]>=0) count_positive++;
else count_negative++;
}
}
if (i==0) score+=(count_positive/2);
else score+= ( (count_positive-count_negative)>0?count_negative:count_positive );
}
printf("%d\n",score);
return 0;
}
int valuate(char c) {
if ( c == '(' ) return 1;
else if ( c == ')' ) return -1;
}
不知道写清楚了没有,有些东西确实——
emm——
比较抽象——
比较个人化的一些东西——
再加上一个语文不好的人写出来的不通顺的一些语句——
能看懂挺好,看不懂的话就算了,独乐乐也行欸嘿~