【BZOJ4922】[Lydsy六月月赛]Karp-de-Chant Number 贪心+动态规划
【BZOJ4922】[Lydsy六月月赛]Karp-de-Chant Number
Description
卡常数被称为计算机算法竞赛之中最神奇的一类数字,主要特点集中于令人捉摸不透,有时候会让水平很高的选手迷之超时。
普遍认为卡常数是埃及人Qa'a及后人发现的常数。也可认为是卡普雷卡尔(Kaprekar)常数的别称。主要用于求解括号序列问题。
据考证,卡(Qa'a)是古埃及第一王朝的最后一位法老。他发现并研究了一种常数,后世以他的名字叫做卡常数。卡特兰数的起源也是因为卡的后人与特兰克斯结婚,生下来的孩子就叫卡特兰,而他只是发表了祖传的家书而已。Sereja也是卡的后人,提出括号序列问题,也是从家书里得到的资料。然而Sereja为了不让这个秘密公开,于是隐瞒了这道题的真正做法。可是由于卡的后人不是各个都像卡特兰一样爱慕虚荣,这一算法也无法找到。“欲见贤人而不以其道,犹欲其入而闭之门也”。卡之常数的奥秘,需要以一颗诚心去追寻。
现给定n个括号序列,你需要选择若干序列,将它们按一定的顺序从左往右拼接起来,得到一个合法的括号序列。
显然,这个问题可以用卡常数解决,为了检验你是否会卡常数,请写一个程序,计算可以得到的合法的括号序列的长度的最大值。
Input
第一行包含一个正整数n(1<=n<=300),表示括号序列的个数。
接下来n行,每行一个长度在[1,300]之间的括号序列,仅由小括号构成。
Output
输出一行一个整数,即最大长度,注意你可以一个序列也不选,此时长度为0。
Sample Input
3
())
((()
)()
())
((()
)()
Sample Output
10
HINT
按{2,1,3}的顺序拼接得到((()()))(),总长度为10。
题解:先用栈求出每个串左边有多少多余的右括号l,右边有多少多余的左括号r。那么我们最终的序列一定是先来一些l<r的,再来一些r<l的。用f[i]表示右面还剩i个多余的左括号时,总长度的最大值,转移时显然是背包,但是转移顺序呢?这就是一个经典的贪心模型了。
对于l<r的,显然我们要先选择l更小的,因为这样可以获得更多的左括号来填掉多余的右括号;对于l>r的就反过来想,先选r更大的。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,m; int f[90010]; struct node { int l,r,v; }p[310]; char str[310]; bool cmp(const node &a,const node &b) { if((a.r>a.l)!=(b.r>b.l)) return (a.r>a.l)>(b.r>b.l); if(a.r>a.l) return a.l<b.l; else return a.r>b.r; } int main() { scanf("%d",&n); int i,j; for(i=1;i<=n;i++) { scanf("%s",str),p[i].v=strlen(str),m+=p[i].v; int top=0; for(j=0;j<p[i].v;j++) { if(str[j]==')') { if(top) top--; else p[i].l++; } else top++; } for(top=0,j=p[i].v-1;j>=0;j--) { if(str[j]=='(') { if(top) top--; else p[i].r++; } else top++; } } sort(p+1,p+n+1,cmp); memset(f,0xc0,sizeof(f)); f[0]=0; for(i=1;i<=n;i++) { if(p[i].r>p[i].l) { for(j=m;j>=p[i].r;j--) f[j]=max(f[j],f[j+p[i].l-p[i].r]+p[i].v); } else for(j=p[i].r;j-p[i].r+p[i].l<=m;j++) f[j]=max(f[j],f[j-p[i].r+p[i].l]+p[i].v); } printf("%d",f[0]); return 0; }
| 欢迎来原网站坐坐! >原文链接<