题目大意:
一个序列中有左括号和右括号,还有问号,问号可以任意转换成左右括号。
问这个序列有多少种情况的转变使得这个序列变成合法的括号匹配序列。
思路分析:
首先我们分析一下,如何使得一个序列是合法的括号匹配序列。
我们很容易想到的是用栈模拟匹配过程。
当遇到左括号就进栈,当遇到右括号就让栈顶的左括号出栈。
那么在模拟的过程中,造成这个序列的不合法的原因只有当右括号来的时候,此时的栈已经为空。
这里补充一句,一旦一个序列给定,那么这里面的问号有多少变成左括号,多少变成右括号,是一定的。
看完以上的过程,也许你能想到这样的一个贪心策略。我们要保证这个序列有解,就让左括号尽量靠左。尽量保证栈内有左括号。
所以我们要做的,就是把问号的左边部分全部变成左括号,剩余的问号再变成右括号。
这样就判断他是否有解。
接下来的问题是判断多解,我们还是按照以上的贪心策略。
但是要退一步考虑。
设 这个序列里有 x 个问号, 其中 lef 个问号变成了左括号, rig 个问号变成了右括号。
那我们把刚好第 lef 个左括号变成右括号,第一个变成右括号的问号变成左括号。
如
((????))
如果按照第一种策略 就变成了
(((())))
再按照第二种策略 就变成了
((()()))
然后再去匹配一次,如果有解,那么就有多解。
thats all
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #define maxn 1000005 #define MAXN 1000005 #define mod 100000000 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 typedef long long ll; using namespace std; int l,r; char str[maxn]; char tmp[maxn]; char stk[maxn]; bool judge(int len)//括号的匹配过程 { int top=-1; for(int i=0;i<len;i++) { if(tmp[i]=='('){ stk[++top]='('; } else { if(top==-1)return false; else top--; } } if(top==-1)return true; return false; } int main() { while(scanf("%s",str)!=EOF) { int len=strlen(str); if(len&1){ printf("None\n"); continue; } l=r=0; int cntl=0,cntr=0; for(int i=0;i<len;i++) { if(str[i]=='(')l++; else if(str[i]==')')r++; } cntl=(len-2*l)/2;//计算多少个问号变成左括号 cntr=(len-2*r)/2;//多少个问号变成右括号 int t=cntl; int posl=-1,posr=-1; for(int i=0;i<len;i++) { if(str[i]=='?') { if(t>0) { tmp[i]='('; t--; if(t==0)posl=i;//最后一个变成左括号的问号的位置 } else { tmp[i]=')'; if(posr==-1)posr=i;//最后一个变成右括号的问号的位置 } } else tmp[i]=str[i]; } if(!judge(len))printf("None\n"); else { if(posl==-1 || posr==-1)printf("Unique\n"); else { swap(tmp[posl],tmp[posr]); if(judge(len))printf("Many\n"); else printf("Unique\n"); } } } return 0; }
hdu 4915 Parenthese sequence (贪心+模拟)
时间: 2024-10-26 13:06:18