HDU 6299 Balanced Sequence 【贪心】

传送门:HDU 6299


Balanced Sequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Problem Description
Chiaki has n strings s1,s2,…,sn consisting of ‘(’ and ‘)’. A string of this type is said to be balanced:
+if it is the empty string
+if A and B are balanced, AB is balanced,
+if A is balanced, (A) is balanced.
Chiaki can reorder the strings and then concatenate them get a new string t. Let f(t) be the length of the longest balanced subsequence (not necessary continuous) of t. Chiaki would like to know the maximum value of f(t) for all possible t.

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases.
For each test case:
The first line contains an integer n (1≤n≤105) – the number of strings.
Each of the next n lines contains a string si (1≤|si|≤105) consisting of ‘(’ and ‘)’.
It is guaranteed that the sum of all |si| does not exceeds 5×106.

Output
For each test case, output an integer denoting the answer.

Sample Input
2
1
)()(()(
2
)
)(

Sample Output
4
2




题意:

给你n个包含’(‘与’)’的字符串,可以将这些字符串任意排序,求所有排序中,子序列是符合正规括号序列的最大长度。

是n个字符串可以自由排序,不是各个字符串可以自由排序。


题解:

可以先将每个字符串中已经合法的括号去除,可以想象,去除后,应该只剩三种情况的字符串(也可以看成一种,另外两种的这一种的特殊情况):

  1. 只剩左括号,如:((( ;
  2. 剩左括号和右括号,右括号一定在左边,如:))( ;
  3. 只剩右括号,如:))) ;

那么我们只要去除合法括号后,用一个结构体存下每个字符串的左括号数目和右括号数目即可。
这时我们又可将这些字符串分成两个部分:

  1. 左括号数目>右括号数目
  2. 左括号数目<=右括号数目

先记左括号数目>右括号数目为正贡献,反之则为负贡献。

我们很自然的就可以想到右括号少的应该放在最前面,因为这些括号一定是浪费了的,当然越少越好。左括号少的应该放在最后面,因为最后的左括号也一定的浪费的。
那么我们就可以得出

1. 当贡献为正时,我们应该以右括号数目由小到大排序
2. 当贡献为负时,我们应该以左括号数目由大到小排序

对于排完序的字符串我们只要模拟走一遍即可。




AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<stack>
#define ll long long
using namespace std;
const int N=110000;
int t,n;
char s[N];
struct Node
{
  int right,left;
}str[N];
int change(char c[],int id)//去除合法括号,并记录长度
{
  stack<char> ss;
  int l=strlen(c);
  int sum=0;
  for(int i=0;i<l;i++)
  {
    if(c[i]=='(')
    {
      str[id].left++;
      ss.push(c[i]);
    }
    else
    {
      if(!ss.empty())
      {
        ss.pop();
        str[id].left--;
        sum+=2;
      }
      else str[id].right++;
    }
  }
  return sum;
}
//记贡献为左括号个数减右括号个数,贡献大于0的在左,小于0的在右
//贡献大于0的按右括号个数由小到大排序,贡献小于0的按左括号个数由大到下排序
bool cmp(Node a,Node b)
{
  if(a.right<=a.left&&b.right>b.left) return true;
  else if(a.right>a.left&&b.right<=b.left) return false;
  else if(a.right<=a.left&&b.right<=b.left) return a.right<b.right;
  else  return a.left>b.left;
}
int main()
{
  scanf("%d",&t);
  while(t--)
  {
    memset(str,0,sizeof(str));
    int ans=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
      scanf("%s",s);
      ans+=change(s,i);
    }
    if(n==1) printf("%d\n",ans);
    else
    {
      sort(str,str+n,cmp);
      int num=0;//记录左括号的数目
      for(int i=1;i<n;i++)
      {
        num+=str[i-1].left;
        if(num>str[i].right)//左括号的数目大于右括号数目
        {
          num-=str[i].right;//取掉右括号的数目
          ans+=2*str[i].right;//长度增加
        }
        else//小于
        {
          ans+=2*num;
          num=0;//左括号全部被匹配
        }
      }
      printf("%d\n",ans);
    }
  }
  return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值