题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6299
题意:给你n个括号序列 按一定顺序排列 使得构成的‘()’对数量最多
思路:很容易可以想到 先将每个括号序列预处理 将已经形成‘()’的去掉 剩下的括号序列一定是形如“))))((”这种
然后在场上这个时候就不会做了 因为要考虑构成最多括号序列 所以各种顺序所构成的序列是非常复杂度 难以寻找一个最优解
赛后看dls的直播重新想了一下 所形成的括号序列一共有以下几种
A:左括号数量多于右括号 例: ))((((
B:左括号数量小于右括号 例:))))((
C:左右括号数量相同
这样如果按一定顺序排 永远不会被匹配的括号一定是最左边的右括号们和最右边的左括号们
所以如果同样是左括号多于右括号 我们肯定要保证将右括号数量少的尽量往前排
例如:))((((( 和 )(((
我们肯定先要保证将 )(((放到))((((前面 因为如果交换顺序 一定会有两个括号无法使用 而这样只是有一个不能使用
但仅仅按此顺序是不完美 我们还要考虑A遇到B的情况
A:))((((
B :))))((
一个是右括号少于左括号 一个是右括号多于左括号 观察可得 我们需要把A放到B前面
而相反情况 则交换
这样就保证了最后形成的序列一定是最优序列 我们的思想就是尽可能少的减少最左边的)的数量
排序很绕 慢慢搞就能搞明白
代码:
#include <iostream>
#include <stack>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
struct node{
int l,r;
};
char str[100010];
bool cmp(node a,node b)
{
if(a.l >= a.r && b.l <= b.r)
{
return true;
}
else if(a.l <= a.r &&b.r <= b.l)
{
return false;
}
if(a.r < a.l && b.r < b.l)
{
return a.r < b.r;
}
return a.l > b.l;
}
int main()
{
int t;
scanf("%d",&t);
node sb[100010];
while(t--)
{
int n;
scanf("%d",&n);
int cnt = 0;
int ans = 0;
for(int i = 1;i <= n;i++)
{
sb[cnt].l = 0;
sb[cnt].r = 0;
scanf("%s",str);
int len = strlen(str);
for(int j = 0;j < len;j++)
{
if(str[j] == ')')
{
if(sb[cnt].l)
{
sb[cnt].l--;
ans += 2;
}
else
{
sb[cnt].r++;
}
}
else
sb[cnt].l++;
}
if(sb[cnt].l==0&&sb[cnt].r==0)
{
continue;
}
cnt++;
}
sort(sb,sb+cnt,cmp);
int zuo = 0;
for(int i = 0;i < cnt;i++)
{
if(sb[i].r <= zuo)
{
ans += 2*(sb[i].r);
zuo -= sb[i].r;
zuo += sb[i].l;
}
else
{
ans += 2*zuo;
zuo = sb[i].l;
}
}
printf("%d\n",ans);
}
return 0;
}