题目原址:http://192.168.49.228/upload/file/20180723/20180723180123_70502.pdf
题目大意:给n个字符串,每个字符串只含有’(’ ‘)’,题目给了一些条件:
+ if it is the empty string
+ if A and B are balanced, AB is balanced,
+ if A is balanced, (A) is balanced.
这样的是正规的串,组合这n个串,形成新的串,使得这样的正规的子串最多,不要求子串是连续的。输出符合的子串的总长度。
学习后,了解到:
对每个串处理删除掉形如”()”这样的子串,最后剩下的子串只会是三种情形。
- 全部是’(’ 。
- 全部是’)’。
- 是”))))((((“这样的。
对剩下左右括号数量统计下来。
接下来就是对n个串排序,使得新组成的正规子串最多。
可以发现形如”((((((“这样的串应当放最前。”))))((((((“这样串分两类,’(‘多于’)’的放靠前,’(‘少于’)’放靠后面。”))))))))”这样的放最后。
“((((“和”))))”好理解为什么这样子安排,”))((((“这样的就可以理解为,要尽可能的吧’(‘放在总体的左边,’)’放在总体的右边,当达到最极致的情况就会使得括号匹配的数量尽可能多。
cmp函数中部分条件只能“感觉”是最优的,但不能证明。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
int l;
int r;
int ans;
}a[100010];
int cmp(node a,node b)
{
if(a.l<=a.r&&b.l>b.r) //)少(多 > )多(少
return true;///不变
if(a.l>a.r&&b.l<=b.r) //)多(少 < )少(多
return false;///让a,b交换
if(a.l<=a.r&&b.l<=b.r)//)少(多 )少(多
return a.l<b.l; //)少的放前面
if(a.l>=a.r &&b.l>b.r)
return a.r>b.r; //(多的优先
}
int main()
{
int f;
char q[100010];
scanf("%d", &f);
while(f--){
int n ;
scanf("%d", &n);
for(int i = 1; i <= n; i ++){
scanf("%s", q);
int len = strlen(q);
a[i].l = a[i].r = a[i].ans = 0;
for(int j = 0; j < len ; j ++){
if(q[j] == '(')
a[i].l ++;
else{
if(a[i].l > 0){
a[i].l --;
a[i].ans++;
}
else
a[i].r++;
}
}
}
sort(a + 1, a + n + 1, cmp);
int r= 0, l = 0;
for(int i = 1; i <= n; i ++){
if(a[i].r > l){
a[i].ans+=l;
l = 0;
}
else{
a[i].ans+=a[i].r;
l-= a[i].r;
}
r+= a[i].ans;
l+= a[i].l;
}
printf("%d\n", r * 2);
}
return 0;
}