HHUOJ 1321
1321: 恶搞指数
时间限制: 1 Sec 内存限制: 32 MB提交: 129 解决: 61
[提交][状态][讨论版][命题人:外部导入]
题目描述
小明的朋友过生日,小明准备了一件礼物,不过小明想恶搞一下他的朋友,所以他准备了一堆盒子,其中有一个盒子里面装了礼物。盒子里面可以再放零个或者多个盒子。假设放礼物的盒子里不再放其他盒子。
用()表示一个盒子,B表示礼物,小明想让你帮他算出恶搞指数,即最少需要拆多少个盒子才能拿到礼物。
用()表示一个盒子,B表示礼物,小明想让你帮他算出恶搞指数,即最少需要拆多少个盒子才能拿到礼物。
输入
输入包含多组测试数据。每组测试数据是一个长度不大于1000,只包含(,)和 B 三种字符的字符串,代表小明设计的礼物透视图。
题目保证每个透视图都是合法的。
题目保证每个透视图都是合法的。
输出
对于每组测试,请在一行里面输出恶搞指数。
样例输入
((((B)()))())
(B)
样例输出4
1
括号嵌套的扩展题。
经历了多次优化,终于把内存压榨到最小。
思路一:利用STL栈。
调用封装好的STL非常舒服,但内存用量排名垫底。
1 #include <iostream> 2 #include <stack> 3 #include <string> 4 using namespace std; 5 int main(void) 6 { 7 string exp; 8 while (cin >> exp) 9 { 10 stack<char> S; 11 for (int i = 0; i < exp.size(); ++i) 12 { 13 if (exp[i] == 'B') 14 break; 15 else 16 { 17 switch (exp[i]) { 18 case '(': 19 S.push(exp[i]); 20 break; 21 case ')': 22 S.pop(); 23 break; 24 } 25 } 26 } 27 printf("%d\n", S.size()); 28 } 29 return 0; 30 }
思路一优化:手写链表模拟栈
本以为会比现成的STL好一点,但貌似还不如STL(境界太低)。可能异常处理占了一部分内存。
代码取自数据结构应用 - 栈,真的从头实现的话太不划算了。
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 struct Node 5 { 6 int value; 7 Node *next; 8 }; 9 10 //创建了一个头节点为S的链栈,S将一直表示栈顶元素 11 Node *CreatStack() 12 { 13 Node *S = new Node; 14 S->next = NULL; 15 return S; 16 } 17 18 int IsEmpty(Node *S) 19 { 20 return S->next == NULL; 21 } 22 void Pop(Node *S) 23 { 24 Node *FirstCell; 25 if(IsEmpty(S))//空栈,将返回异常 26 cout << "Empty Stack" << endl; 27 else 28 { 29 FirstCell = S->next;//取出栈顶 30 S->next = S->next->next;//使S指向新的栈顶 31 delete FirstCell;//删除原栈顶,完成出栈 32 } 33 } 34 void Push(int x, Node *S) 35 { 36 Node *TempCell = new Node; 37 if (TempCell == NULL) 38 cout << "Out of space" << endl; 39 else 40 { 41 TempCell->value = x;//把x赋值给value 42 TempCell->next = S->next;//将新节点设为栈顶 43 S->next = TempCell;//使S指向新的栈顶 44 } 45 } 46 int Print(Node *S) 47 { 48 int cnt = 0; 49 Node *p = S->next;//将p初始化为栈顶 50 while (p != NULL) 51 { 52 cnt++; 53 p = p->next; 54 } 55 return cnt; 56 } 57 58 int main(void) 59 { 60 string exp; 61 while (cin >> exp) 62 { 63 Node *S = CreatStack(); 64 for (int i = 0; i < exp.size(); ++i) 65 { 66 if (exp[i] == 'B') 67 break; 68 else 69 { 70 switch (exp[i]) { 71 case '(': 72 Push(exp[i],S); 73 break; 74 case ')': 75 Pop(S); 76 break; 77 } 78 } 79 } 80 printf("%d\n", Print(S)); 81 } 82 return 0; 83 }
思路二:重新思考。
想不通前面的人怎么能把内存压缩到那么小,肯定是算法本身不够优(甩锅给STL失败...)
前面的思路基本是基于括号嵌套这一母题来做的,借鉴的是栈混洗。
而这道题与母题不同的是,这次给出的表达式一定是括号匹配的,而且多出了一个礼物B。这不就是天然的二分法吗...
前面的思路中,要拆开的层数就是最后留在栈中的左括号的数量,但其实仔细观察,B前面的左括号数和B后面的右括号数应该是一样多的。
实现如下:
1 #include <stdio.h> 2 #include <iostream> 3 #include <string> 4 using namespace std; 5 int main() 6 { 7 string s; 8 int num, i; 9 while (cin>>s) 10 { 11 num = 0; 12 for (i = 0; i < s.size(); i++) 13 { 14 if (s[i] == 'B')break; 15 else if (s[i] == '(')num++; 16 else num--; 17 } 18 printf("%d\n", num); 19 } 20 return 0; 21 }
思路二优化:string及cin优化
对于dalao来说根本不存在这一步优化。
但实际上思路二实现后与思路一相比进步还不够。
完全抛弃C++改用纯C后能进一步优化。
1 #include <stdio.h> 2 #include <string.h> 3 int main() 4 { 5 char exp[1000]; 6 while (scanf_s("%s",exp) != EOF) 7 { 8 int num = 0; 9 int i; 10 for (i = 0; i < strlen(exp); i++) 11 { 12 if (exp[i] == 'B')break; 13 else if (exp[i] == '(')num++; 14 else num--; 15 } 16 printf("%d\n", num); 17 } 18 return 0; 19 }
这样应该是把C的效率压榨到头了。
题是水题,但还是有一点启发的,那就是,我再也不要手写STL了(逃