题意
给n个由'('和')'组成的串,问按一定顺序排序后最多有多少个合法匹配的串。
题解
先将每个串中已经匹配好的串,用栈来去除,会得到一些串三种")))","(((",")))((("。
所以每个串都有左括号个数和右括号个数的值,就用这两个值来排序。
排序方式:有两种,从左至右的链接串,从右往左的链接串(两者排序方式相反)。
从左至右:a[1]+a[2]+a[3]+...+a[n]。
1.左括号多右括号少的串放在左括号少右括号多串前面(这样保证左括号尽量能在前面,右括号能在后面)。
2.左括号和右括号都是一样多,左括号多的在前。
3.其他情况右括号在少的在前
从右至左:a[n]+a[n-1]+...+a[1]。
代码1
//从左至右
#include<bits/stdc++.h>
using namespace std;
struct node
{
int l,r,nu;//l左括号,r右括号
bool operator < (const node& aa)const
{
if(l<=r&&aa.l>aa.r)//左少右多 & 左多右少
{
return false;
}
if(l>r&&aa.l<=aa.r)//左多右少 & 左少右多
{
return true;
}
if(r>=l&&aa.r>=aa.l)//左少右多 &7左少右多
{
return l>aa.l;
}
return r<aa.r;//其他情况按右括号的顺序排序
}
}a[100010];
char ss[100010];
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",ss);
int len=strlen(ss);
int num1=0,num2=0,num=0;
for(int j=0;j<len;j++)
{
if(ss[j]=='(')
num1++;
else {
if(num1)
num++,num1--;
else
num2++;
}
}
a[i].l=num1;
a[i].r=num2;
a[i].nu=num;
}
sort(a,a+n);
long long ans=0;
long long pre=0; //前面没匹配的左括号
for(int i=0;i<n;i++)
{
ans+=a[i].nu;
if(pre&&a[i].r) //前面有没匹配的左括号,当前有右括号
{
if(pre>a[i].r) //如果前面左括号多于当前右括号
{
ans+=a[i].r;
pre-=a[i].r;
}
else ans+=pre,pre=0;
}
pre+=a[i].l;
}
printf("%lld\n",ans*2);
}
return 0;
}
代码2
//从右至左
#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MOD = 1e6 + 7;
const int maxn = 1e5 + 10;
struct Node {
int l, r;
}node[maxn];
char str[maxn];
char st[maxn*50];
bool cmp(Node a, Node b)
{
if(a.l >= a.r && b.l < b.r) //左括号多右括号少的,放后面(就是放左边)
return false;
if(a.l < a.r && b.l >= b.r) //右括号多左括号少的,放前面(就是放右边)
return true;
if( a.l>=a.r && b.l>=b.r)
return a.r > b.r;
return a.l < b.l;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
ll ans = 0;
for(int i = 1; i <= n; i++)
{
scanf("%s", str);
int len = strlen(str);
node[i].l = 0;
node[i].r = 0;
int top = 0;
for(int j = 0; j < len; j++)
{
if(str[j]==')'&&top>0&&st[top]=='(')
{
ans++;
top--;
}
else st[++top]=str[j];
}
while(top) {
if(st[top] == ')') {
node[i].r++;
}
else
{
node[i].l++;
}
top--;
}
}
sort(node+1, node+n+1, cmp);
for(int i = 1; i <= n; i++)
{
printf("l: %d r: %d\n", node[i].l, node[i].r);
}
int now=0; //前面没匹配的右括号
for(int i = 1; i <= n; i++)
{
if(node[i].l > now) //当前左括号多于前面右括号
{
node[i].l = now;
}
ans += node[i].l;
now -= node[i].l; //匹配好的右括号去掉
now += node[i].r;
}
printf("%I64d\n", ans*2);
}
return 0;
}