题意:给你n个只含'(' ')'的字符串, 你可以将这些字符串左右端随意连接成一个新串,然后求出能得到的符合条件的 最长子序列。
条件:(1) 空串符合 (2) 如果A符合则 (A)也符合 (3)如果A,B符合则 AB也符合 : 总言之就是将这个括号串放入栈中,如果能够全部弹出则为符合条件的串(左右括号匹配就弹出)
思路:关于这道题,一开始可能不会想到贪心。(读题都读到自闭..)但是后面会发现要使子序列最长,我们肯定希望在某个串中最近的两个左右括号匹配
比如 ) ( ( ) ( ( ) ,我们肯定希望2与4匹配而不是与7匹配, 即只要在串中右两个匹配即把它算到最长子序列的串中。
这样以来我们取完这匹配好的括号后就只剩 ) ( ( , 上面样例字符串。即任何一个字符串匹配完最后会出现左右括号剩余(或者没有)的情况
接下来就是讨论像多个串有 ) ( 这种形式如何最大匹配。首先按照贪心的想法,我们肯定要让两个串左右两边尽可能接近这样不会浪费括号。
当我们匹配相邻的两个串时,比如 a: )))( b:)(( ,我们会找左右括号哪边更大:a的右括号数大于左括号,b的左括号数大于右括号,所以大大匹配,这两个就要交换位置
如果 a:)))(( b:))( 两边都是右括号小于左括号,则我们希望两个串左括号或者右括号数目更多的进行匹配。 当然反之同理(就是右括号比左括号多的情况)
所以这样我们就得到了贪心的排序:
if(a.l > a.r) return b.l > b.r? a.r < b.r : true; if(a.l <= a.r) return b.l <= b.r? a.l > b.l : false;
code:
#include <cstring> #include <cstdio> #include <iostream> #include <algorithm> #include <string> using namespace std; const int maxn = 1e5+10; struct node{ int l,r; }p[maxn]; bool cmp(node a,node b){ if(a.l > a.r) return b.l > b.r? a.r < b.r : true; if(a.l <= a.r) return b.l <= b.r? a.l > b.l : false; } char s[maxn]; int main(){ int n; int T; scanf("%d",&T); while(T--){ scanf("%d",&n); int ans = 0; for(int i = 1;i <= n;i++){ scanf("%s",s); int len = strlen(s); p[i].l = p[i].r = 0; for(int j = 0;j < len;j++){ if(s[j] == '(') p[i].l++; else{ if(p[i].l > 0){ p[i].l--; ans += 1; } else{ p[i].r++; } } } } sort(p+1,p+n+1,cmp); int l=0; for(int i=1; i<=n; i++) { if(p[i].r<=l) ans+=p[i].r,l-=p[i].r; else ans+=l,l=0; l += p[i].l; } printf("%d\n",ans*2); } return 0; }