題意
給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;
}