贪心+最优策略 7.23杭电多校赛 B

2.

Balanced Sequence

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1432 Accepted Submission(s): 352

 

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

 

Source

2018 Multi-University Training Contest 1

Recommend

liuyiding | We have carefully selected several similar problems for you: 6308 6307 6306 6305 6304

 

题目大意:

​ 已知n个由'(',')'组成的字符串,问把它们按任意顺序连接后的字符串中有多少个()。

 

想法:

​ 单个字符串内有几个()用栈来判断就好了(像求波兰表达式)。关键是怎么求最优的头尾相连顺序。

一刷发现:根本不用栈好吗,只前面有'('后,再放')',肯定就匹配了的。第一次提交居然超时了,然后把cin取消同步了,居然就过了,951ms,吐血。

思路:

​ 1、剔除字符串内的(),最后会只剩下l个'(',r个‘)’。统计 add=()的个数,l = 剩下的'('个数,r = 剩下的')'个数

​ 2、贪心,最优排序。左少右多在前半部分,左少在前。左多右少在后半部分,右少在前。这样头尾浪费最少,中间匹配最多。

​ 3、计算结果,注意有多种情况。now = 前面剩下的'(' 。now>a[i].l:匹配完后还会剩下,now-=a[i].l,不能now=0。now<a[i].l: 只能匹配now个,然后要now=0

 

标准题解

​.

AC代码:

// B
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 101010;
const int MAXS = 101010;
int n;
class Str
{
public:
    int l, r, add;
    bool operator <(const Str &b) const
    {
        if(l >= r && b.l < b.r)     //左多右少在后 
            return false;
        if(l < r && b.l >= b.r)     //左少右多在前 
            return true;        
        if(l >= r && b.l >= b.r)    //右少在前 
            return r > b.r; 
        return l < b.l;             //左少在前 
    }
}a[MAXN];
char s[MAXS];
void solve()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%s", s);
        int len = strlen(s);
        a[i].l = a[i].r = a[i].add = 0;
        for(int j = 0; j < len; j++)
        {
            if(s[j] == '(')
                a[i].r++;
            else
            {
                if(a[i].r > 0)
                    a[i].r--, a[i].add++;  //减1个(,加匹配个数 
                else
                    a[i].l++;
            }
        }
    }
    sort(a + 1, a + n + 1);
    int ans = 0;
    int now = 0;
    for(int i = 1; i <= n; i++)
    {
        if(a[i].l > now)            //可能大于前面的'('数,那也只能匹配那么多 
            a[i].l = now;
        ans += a[i].l + a[i].add;   
        now -= a[i].l;              //减去匹配的以后,可能还剩下'('留给后面的 
        now += a[i].r;
    }
    printf("%d\n", ans * 2);
}
int main()
{
    int T;
    scanf("%d", &T);
    for(int t1 = 1; t1 <= T; t1++)
        solve();
    return 0;
}

一刷代码(接近超时)

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
 
typedef long long ll;
​
/*
1
4
)((()()((
))((( 
))(((
))))(
​
*/
​
struct item{
    int l,r;
};
​
//vector<char> v;           用栈超时了。。。不知道为啥 ,而且后来发现根本不用栈 
char a[100005];
item last[100005]; 
​
bool cmp(item x,item y){
    if(x.l<x.r && y.l>=y.r){        //左少右多在前 
        return true;
    }
    if(x.l>=x.r && y.l<y.r){        //左多右少在后 
        return false;
    }
    if(x.l<x.r && y.l<y.r){         //左少右多  左少在前 
        return x.l < y.l;
    }   
    return x.r > y.r;                   //左多右少  右少在后 
}
​
int main()
{
    ios::sync_with_stdio(false);//取消同步
    std::cin.tie(0);//解除cin与cout的绑定,进一步加快执行效率。
    int T;
    cin >> T;
    while(T--){
        int ans = 0;
        int N;
        cin >> N;
        /* 
        for(int i=0;i<N;i++){
            cin >> a;
            v.clear();
            v.push_back(a[0]);
            last[i].l = 0;
            last[i].r = 0;
            if(a[0] == ')'){
                last[i].l++;
            }else{
                last[i].r++;
            }
            for(int j=1;j<strlen(a);j++){
                if(!v.empty() && v[v.size()-1] == '(' && a[j]==')'){
                    v.pop_back();
                    ans++;
                    last[i].r--;
                }else{
                    v.push_back(a[j]);
                    if(a[j] == ')'){
                        last[i].l++;
                    }else{
                        last[i].r++;
                    }
                }
            }
        }
        */
        for(int i=0;i<N;i++){
            cin >> a;
            last[i].r=last[i].l=0;
            for(int j=0;j<strlen(a);j++){
                if(a[j]=='('){
                    last[i].r++;
                }else{
                    if(last[i].r>0){
                        last[i].r--;
                        ans++;
                    }else{
                        last[i].l++;
                    }
                }
            }
        }
        sort(last,last+N,cmp);
        /*      
        for(int i=0;i<N;i++){
            cout << last[i].l << " " << last[i].r << endl;
        }
        */  
        int have_r = last[0].r;
        for(int i=1;i<N;i++){
            if(have_r < last[i].l){
                last[i].l = have_r;
            }
            ans += last[i].l;
            have_r -= last[i].l;
            have_r += last[i].r;
        } 
        cout << ans*2 << endl;
    }
}
​

 

参考:

https://www.ideone.com/Wo55gi

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值