HDU6299 2018多校第一場(貪心)

題意

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

 

發佈了84 篇原創文章 · 獲贊 9 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章