分析:
非常套路:每个括号串可以将其内部的括号匹配掉,最终肯定是左边一段连续的")",右边一段连续的"(" (都可能为0)
然后将其表示为二元组(x,y)
当x>y时,加上当前这个串后,括号层数一定会更大,那么肯定比x<=y的要先放。
而要放一个括号串,其要求必须之前的层数不低于x,那么此时就按照x升序排列就好了。(如果某个方案中,x更大的放在更前面,那么交换两者一定还是合法的)
而x<=y的部分也是这样,将上面的反过来考虑即可:要放一个括号串,要求之后的层数不低于y,那么就按照y降序排列就好了。
排好序之后,就成了个傻逼背包题。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 310
using namespace std;
int dp[2][MAXN*MAXN];
struct node{
int minv,sumv,len,id;bool operator < (const node & a) const {
if(sumv>=0&&a.sumv<0)return 1;if(sumv<0&&a.sumv>=0)return 0;if(sumv>=0&&a.sumv>=0)return minv>a.minv;return sumv-minv>a.sumv-a.minv;}
}blo[MAXN];
int n;
char s[MAXN];
int main(){
SF("%d",&n);for(int i=1;i<=n;i++){
SF("%s",s);int minv=0;int sumv=0;int len=strlen(s);for(int j=0;j<len;j++){
if(s[j]=='(')sumv++;elsesumv--;minv=min(minv,sumv);}blo[i].minv=minv;blo[i].sumv=sumv;blo[i].len=len;blo[i].id=i;}sort(blo+1,blo+1+n);
// for(int i=1;i<=n;i++)
// PF("<%d %d %d %d>\n",blo[i].minv,blo[i].sumv,blo[i].len,blo[i].id);int now=0;memset(dp,-1,sizeof dp);dp[0][0]=0;for(int i=1;i<=n;i++){
now^=1;memset(dp[now],-1,sizeof dp[now]);for(int j=0;j<=90000;j++){
int j1=j+blo[i].sumv;dp[now][j]=max(dp[now][j],dp[now^1][j]);if(j+blo[i].minv>=0&&j1>=0&&j1<=90000&&dp[now^1][j]!=-1)dp[now][j1]=max(dp[now][j1],dp[now^1][j]+blo[i].len);}
// for(int j=0;j<=43;j++)
// PF("[%d %d]",j,dp[now][j]);
// PF("\n--------------------------\n");}PF("%d\n",dp[now][0]);
}