HDU6299 2018多校第一场(贪心)

题意

给n个由'('和')'组成的串,问按一定顺序排序后最多有多少个合法匹配的串。

题解

先将每个串中已经匹配好的串,用栈来去除,会得到一些串三种")))","(((",")))((("。

所以每个串都有左括号个数和右括号个数的值,就用这两个值来排序。

排序方式:有两种,从左至右的链接串,从右往左的链接串(两者排序方式相反)。

从左至右:a[1]+a[2]+a[3]+...+a[n]。

1.左括号多右括号少的串放在左括号少右括号多串前面(这样保证左括号尽量能在前面,右括号能在后面)。

2.左括号和右括号都是一样多,左括号多的在前。

3.其他情况右括号在少的在前

从右至左:a[n]+a[n-1]+...+a[1]。

扫描二维码关注公众号,回复: 2360060 查看本文章

代码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;
}

猜你喜欢

转载自blog.csdn.net/QiHang_QiHang/article/details/81189617