【洛谷 1944】DP / 栈 / 玄学做法

题意:

(1) 空的括号序列是美观的;

(2) 若括号序列 A 是美观的,则括号序列(A)、[A]、{A}也是美观的;

(3) 若括号序列 A、B 都是美观的,则括号序列 AB 也是美观的;

     例如 [(){}]() 是美观的括号序列,而 )({)[}]( 则不是。

     现在所给的括号序列中,找出其中连续的一段,满足这段子序列是美观的,并且长度尽量大。

  今天集训第一题就是它【洛谷1944】,只是换了一下输出,输出最长的美观的连续子序列的长度。

  刚开始做的时候,还想着这是栈的经典例题,然后我就不知道为什么打了个队列,没错!!就是队列!! 我怕是石乐智了(两个样例还过了一个)!!!!陆陆续续调了一天!!!!!!这时候才想起来是栈。。。。。

  还有一点:别忘了判断栈是否已经为空!!!!!!

 


题解:

  • 方法一:
 1 #include <cstdio>
 2 #include <string>
 3 #include <stack>
 4 #include <iostream>
 5 
 6 std::string s;
 7 
 8 int ans, maxn;
 9 
10 void fs() {
11     std::stack<char> q;
12     int len = s.length();
13     for (int i = 0; i < len; ) {
14         while (s[i] == '(' || s[i] == '[' || s[i] == '{') {
15             q.push(s[i++]);
16         }
17             
18         if (s[i] == ')') {
19             if (!q.empty() && q.top() == '(') {                    // !!!!!判断是否栈空,为此我 RE 了 4 个点
20                 q.pop(), ans += 2, i++;
21                 if (maxn < ans) maxn = ans;
22             } else {
23                 while (s[i] == ')' || s[i] == ']' || s[i] == '}') i++;
24                 while (!q.empty()) q.pop();
25                 ans = 0;
26             }
27         } else if (s[i] == ']') {
28             if (!q.empty() && q.top() == '[')  {
29                 q.pop(), ans += 2, i++;
30                 if (maxn < ans) maxn = ans;
31             } else {
32                 while (s[i] == ')' || s[i] == ']' || s[i] == '}') i++;
33                 while (!q.empty()) q.pop();
34                 ans = 0;
35             }
36         } else if (s[i] == '}') {
37             if (!q.empty() && q.top() == '{')  {
38                 q.pop(), ans += 2, i++;
39                 if (maxn < ans) maxn = ans;
40             } else {
41                 while (s[i] == ')' || s[i] == ']' || s[i] == '}') i++;
42                 while (!q.empty()) q.pop();
43                 ans = 0;
44             }
45         }
46     }
47     
48 }
49 
50 int main() {
51     freopen("sequence.in", "r", stdin);
52     freopen("sequence.out", "w", stdout);
53     
54     std::cin >> s;
55     
56     fs();
57     
58     printf("%d\n", maxn);
59     return 0;
60 }

 

  • 方法二:DP
 1 #include <cstdio>
 2 #include <string>
 3 #include <iostream>
 4 
 5 const int MAXN = 1000050;
 6 
 7 std::string s;
 8 
 9 int dp[MAXN], maxn = 0, max, t;                   // dp数组代表以第i个元素结尾的最长子序列长度
10                                       // 还有一种dp方法是dp[i]代表以第i个元素开头的最长子序列长度,从后向前dp 11 int main() { 12 freopen("sequence.in", "r", stdin); 13 freopen("sequence.out", "w", stdout); 14 15 std::cin >> s; 16 17 int len = s.length(); 18 19 for (int i = 0; i < len; i++) { 20 if (s[i] == '(' || s[i] == '[' || s[i] == '{') continue; 21 else if ((s[i] == ')' && s[i - 1 - dp[i - 1]] == '(') || (s[i] == ']' && s[i - 1 - dp[i - 1]] == '[') || ((s[i] == '}' && s[i - 1 - dp[i - 1]] == '{'))) { 22 dp[i] = dp[i - 1] + 2; 23 if (i - 2 - dp[i - 1] < 0) t = 0;          // 防止越界 24 else t = dp[i - 2 - dp[i - 1]]; 25 dp[i] += t; 26 if (dp[i] > maxn) maxn = dp[i], max = i; 27 } 28 } 29 30 printf("%d\n", maxn); 31 32 33 return 0; 34 }

  

  • 方法三:其实同方法一
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int n, p, ans, len, f[100010];
 7 char s[100010]; 
 8 int main() {
 9     freopen("sequence.in","r",stdin);
10     freopen("sequence.out","w",stdout);
11     scanf("%s", s);
12     n = strlen(s); p = 0;
13     for (int i = 0; i < n; i++) {
14         p = 0;
15         for (int j = i; j < n; j++) {
16             if (s[j] == '(') f[++p] = ')';
17             else if (s[j] == '[') f[++p] = ']';
18             else if (s[j] == '{') f[++p] = '}';
19             else if (!p || s[j] != f[p]) break;
20             else {
21                 p--;
22                 if (!p) ans = max(ans, j - i + 1);
23             }
24         }
25     }
26     cout << ans << endl;
27 }

 

posted @ 2017-10-16 17:13  E-Valley  阅读(178)  评论(0)    收藏  举报