HDU6299
贪心思想
多组输入,给你多个字符串,字符串间可以任意自由组合,求你取得能够得到最多的()的数量,
首先看到左右括号的配对,想到栈,或者用数组来简化字符串,即到最后字符串有三种形式。
1.只有’(’。
2.只有’)’。
3.既有’)’,也有’(’,组合即为类似‘)))(((’这样的字符串。
空串不予考虑。
第一,第二种的情况都好考虑,第三种相对来说要更加复杂。
对于第一种把其字符串全部放在开头,对于第二种,把其字符串全部放在结尾。
对于第三种分两种情况,贪心的思想
1)如果左括号‘(’多于右括号‘)’,那么按照右括号’)‘从小到大排序。
2)如果左括号’(‘少于右括号’(‘,那么按照左括号’(‘从大到小排序。
上代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstring>
#include <vector>
using namespace std;
#define maxn 100010
const int mod = 1e9+7;
struct node{
int l, r; //分别代表左括号的数量和右括号的数量
bool operator < (const node b){
if(l>=r&&b.l>=b.r) return r<b.r; //如果左括号大于右括号,按照右括号从小到大排序
else if(l>=r&&b.l<b.r) return 1; //位置不变
else if(l<r&&b.l>=b.r) return 0; //位置交换
else return l>b.l; //如果左括号小于右括号,按照左括号从大到小排序
}
};
char str[maxn];
int main(){
ios::sync_with_stdio(0); //cin优化
int k;
scanf("%d", &k);
while(k--){
int n;
scanf("%d", &n);
int ans = 0; //记录左右括号匹配的对数,所以到后面要乘2
vector<node> v; //这个v是用来存储既有左括号又有右括号的字符串,这种方式大大降低了运行时间
//如果是用来存储全部的字符串的话,运行时间在900ms多,但用这种只用了100ms多
int suml = 0, sumr = 0; //记录总共的只有左括号和只有右括号的字符串的数量
for(int i = 0; i < n; i++){
int l = 0, r = 0;
scanf("%s", str);
for(int j = 0; j < strlen(str); j++){
if(str[j]==')'&&l!=0) l--, ans++; //只有一种情况是ans要加一的
else if(str[j] == ')') r++;
else if(str[j] == '(') l++;
}
if(l==0&&r!=0) sumr+=r; //只有右括号
else if(l!=0&&r==0) suml+=l; //只有左括号
else if(l!=0&&r!=0) v.push_back(node{l, r}); //既有左括号又有右括号
}
sort(v.begin(), v.end()); //对v排序
int tmp = suml; //tmp表示当前拥有的左括号的数量
for(int i = 0; i < v.size(); i++){
if(tmp >= v[i].r){ //如果tmp大于等于v[i].r,即表示可以完全配对该字符串的右括号
ans += v[i].r;
tmp += v[i].l;
tmp -= v[i].r;
}else { //否则表示最多只能配对tmp对左右括号,然后对tmp进行重置
ans += tmp;
tmp = v[i].l;
}
}
ans += min(sumr, tmp); //加上最后的右括号
printf("%d\n", ans*2);
}
return 0;
}