题意:
现给定n个括号序列,你需要选择若干序列,将它们按一定的顺序从左往右拼接起来,得到一个合法的括号序列。计算可以得到的合法的括号序列的长度的最大值。
题解:
题解:
首先对于每个括号序列,把左边的左括号和右边的右括号对消,最后能得到一坨这样的东西:
))…))((…((
就是x个右括号然后y个左括号,记作(x,y)
然后考虑假如我们的子集选好了,我们要按照什么顺序拼接才能拼成一个合法的括号序列呢?
BZOJ3709
能拼必须满足当前左括号数≥x,拼完后左括号数+=y−x
显然先拼y≥x的,后拼y<x的
先考虑y≥x,显然拼了会使左括号数增大,那么能拼就拼,顺序是按照x从小到大
然后y<x,考虑倒着做,从后往前拼,能拼必须满足当前右括号数≥y,拼完后右括号数+=x−y,所以顺序是按照y从小到大,正过来就是从大到小
那么我们把所有的二元组按照上述顺序排序后,以左括号数作为空间跑一遍背包就行了
注意由于物品大小有正有负所以要讨论一下枚举顺序。。。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const ll INFF=0x3f3f3f3f3f3f3f3f;
const double pi=acos(-1.0);
const double eps=1e-9;
char str[505];
int f[305][305*305];
struct node
{
int x,y,len;
}a[305],a1[305],a2[305];
bool cmp1(node p1,node p2)
{
return p1.x<p2.x;
}
bool cmp2(node p1,node p2)
{
return p1.x+p1.y>p2.x+p2.y;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",str);
int len=strlen(str);
int now=0;
a[i].x=0;
for(int j=0;j<len;j++)
{
if(str[j]==')')
now--;
else
now++;
a[i].x=max(a[i].x,-1*now);
}
a[i].len=len;
a[i].y=now;
}
int cnt1=0,cnt2=0;
for(int i=1;i<=n;i++)
{
if(a[i].y>=0)
a1[++cnt1]=a[i];
else
a2[++cnt2]=a[i];
}
//printf("%d%d",cnt1,cnt2);
sort(a1+1,a1+cnt1+1,cmp1);
sort(a2+1,a2+cnt2+1,cmp2);
for(int i=1;i<=cnt2;i++)
a1[i+cnt1]=a2[i];
int s=0;
memset(f,0xef,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=s;j++)
{
f[i][j]=f[i-1][j];
}
for(int j=a1[i].x;j<=s;j++)
{
f[i][j+a1[i].y]=max(f[i][a1[i].y+j],f[i-1][j]+a1[i].len);
}
s+=a1[i].len;
}
printf("%d\n",f[n][0]);
return 0;
}
括号序列拼接问题
本文探讨了如何从多个括号序列中选择并拼接成一个合法括号序列的方法。通过将序列转换为(x,y)形式,并根据x和y的不同进行排序,最终使用动态规划求得最大合法括号序列长度。
634

被折叠的 条评论
为什么被折叠?



