HDU 6299 Balanced Sequence(流水线调度贪心)

题目链接:Balanced Sequence

题意

给出 n n 个只包含左右括号的字符串,将这些字符串拼起来,要求最终拼出来的括号序列中,最长的完全匹配括号子序列的长度最长,问最长子序列长度。

输入

第一行为一个整数 T,接下去有 T T 组数据,每组数据第一行为一个整数 n (1n105),后面 n n 行每行为一个只包含左右括号的字符串 si (1|si|105),数据保证 |si| | s i | 的和不超过 5×106 5 × 10 6

输出

输出最长完全匹配子序列长度。

样例

输入
2
1
)()(()(
2
)
)(
输出
4
2
题解

可以发现,每个字符串中,已经匹配的左右括号,不论以任何顺序与其他字符串连接,这些已经匹配的左右括号对都不会改变,用栈模拟匹配后,最后只会剩下最前面的 l l ) 和最后面的 r(,类似 )))(( 的形式,只有这些括号在和其他字符串匹配的时候才会产生新的括号匹配子序列。
如果字符串 a a al) ar a r (,字符串 b b bl) br b r (,将 a a 放在 b 的前面(不必相邻),则会产生 x=min(ar,bl) x = min ( a r , b l ) 对新的括号匹配子序列,将 b b 放在 a 的前面,则会产生 y=min(br,al) y = min ( b r , a l ) 对新的括号匹配子序列,现在贪心地对所有字符串进行排序,如果 x>y x > y ,则把 a a 排在 b 的前面,如果 x<y x < y 大,则把 b b 排在 a 的前面,如果 x=y x = y ,则把含有 ( 个数多的放在前面,最后扫一遍整个排序拼接后的字符串,就可以计得到答案。

过题代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
using namespace std;

#define LL long long
const int maxn = 100000 + 100;
struct Node {
    int l, m, r;
    Node() {
        l = m = r = 0;
    }
    Node(int L, int M, int R) {
        l = L;
        m = M;
        r = R;
    }
};

bool operator<(const Node &a, const Node &b) {
    int aa = min(a.r, b.l);
    int bb = min(b.r, a.l);
    if(aa == bb) {
        return a.r > b.r;
    }
    return aa > bb;
}

int T, n;
char str[maxn];
Node node[maxn];

Node Get() {
    int len = strlen(str + 1);
    Node ret;
    ret.l = ret.r = 0;
    for(int i = 1; i <= len; ++i) {
        if(str[i] == ')') {
            if(ret.r != 0) {
                --ret.r;
            } else {
                ++ret.l;
            }
        } else {
            ++ret.r;
        }
    }
    ret.m = len - ret.l - ret.r;
    return ret;
}

int main() {
    #ifdef Dmaxiya
    freopen("test.txt", "r", stdin);
    #endif // Dmaxiya
    ios::sync_with_stdio(false);

    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for(int i = 0; i < n; ++i) {
            scanf("%s", str + 1);
            node[i] = Get();
        }
        sort(node, node + n);
        Node tmp = node[0];
        Node ll = node[0];
        Node rr;
        for(int i = 1; i < n; ++i) {
            rr = node[i];
            tmp.l = rr.l + ll.l - min(ll.r, rr.l);
            tmp.r = ll.r + rr.r - min(ll.r, rr.l);
            tmp.m = ll.m + rr.m + 2 * min(ll.r, rr.l);
            ll = tmp;
        }
        printf("%d\n", tmp.m);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值