括号匹配 (区间dp)

区间dp

题目大意:给出一个的只有’(‘,’)’,’[‘,’]’四种括号组成的字符串,求最多有多少个括号满足匹配。
题目链接
思路:用dp[i][j]表示区间i~j的最大匹配数,对于dp[i][j] = dp[i + 1][j - 1] + (s[i]和s[j]匹配?2 : 0),开始时dp[i][j]均为0。
代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

const int maxn = 1e2 + 100;
char str[maxn];
int dp[maxn][maxn];

int main()
{
    while(~scanf("%s", str) && strcmp(str, "end"))
    {
        memset(dp, 0, sizeof(dp));
        int n = strlen(str);
        for(int len = 2; len <= n; len++)
        {
            for(int i = 0; i < n; i++)
            {
                if(i + len - 1 > n) break;
                int j = i + len - 1;
                if((str[i] == '(' && str[j] == ')') || (str[i] == '[' && str[j] == ']'))
                {
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                }
                else dp[i][j] = dp[i + 1][j - 1];

                for(int k = i; k < j; k++)
                {
                    dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j]);
                }
            }
        }
        printf("%d\n", dp[0][n - 1]);
    }
}

括号匹配升级:
问最少加多少括号,能使其完全匹配。加上个记录路径。
比如:( [ ( ] 最少加两个 变为 ( ) [ () ]

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

const int maxn = 1e2 + 100;
const int INF = 0x3f3f3f3f;
char str[maxn];
int dp[maxn][maxn], tag[maxn][maxn];

// tag[i][j]用于记录区间[i, j]在哪里断开
// dp[i][j]表示区间[i, j]最少的不匹配的数量。

void print(int l, int r) {
   if(l > r) return ;
   if(l == r) {
      if(str[l] == '(' || str[r] == ')') printf("()");
      else printf("[]");
      return ;
   }
   if(tag[l][r] == -1) {
      printf("%c", str[l]);
      print(l + 1, r - 1);
      printf("%c", str[r]);
   }
   else {
      print(l, tag[l][r]);
      print(tag[l][r] + 1, r);
   }
}

int main()
{
    while(~scanf("%s", str))
    {
        memset(dp, 0, sizeof(dp));
        memset(tag, -1, sizeof(tag));
        int n = strlen(str);
        if(n == 0) {
        printf("\n");
        continue;
     }
        for(int i = 0; i <= n; i++) dp[i][i] = 1; //一个的时候是1

        for(int len = 2; len <= n; len++)
        {
            for(int i = 0; i < n; i++)
            {
                if(i + len - 1 >= n) break;
                int j = i + len - 1;
                dp[i][j] = dp[i + 1][j - 1];
                if((str[i] == '(' && str[j] == ')') || (str[i] == '[' && str[j] == ']'))
                { }
                else dp[i][j] += 2;
                //当str[i]与str[j]匹配时,dp[i][j] = dp[i + 1][j - 1]
                //不匹配时,加2

                for(int k = i; k < j; k++)
                {
                    if(dp[i][j] >= dp[i][k] + dp[k + 1][j]) { //要加=号是因为']('这样的情况,在没进第三个for的时候就已经变成了2,[0,1]区间应该被分割开加符号,但是tag记录不到。
                        dp[i][j] = dp[i][k] + dp[k + 1][j];
                        tag[i][j] = k;
                    }
                }
            }
        }

        print(0, n - 1);
        printf("\n");
    }
}

附紫书上的做法:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e3 + 100;
const int inf = 0x3f3f3f3f;

int dp[maxn][maxn], tag[maxn][maxn];
char str[maxn];

bool match(char a, char b) {
   if((a == '(' && b == ')') || (a == '[' && b == ']')) return true;
   return false;
}

void print(int l, int r) {
   if(l > r) return ;
   if(l == r) {
      if(str[l] == '(' || str[r] == ')') printf("()");
      else printf("[]");
      return ;
   }
   if(tag[l][r] == -1) {
      printf("%c", str[l]);
      print(l + 1, r - 1);
      printf("%c", str[r]);
   }
   else {
      print(l, tag[l][r]);
      print(tag[l][r] + 1, r);
   }
}

int main()
{
     gets(str);
     int len = strlen(str);
     if(len == 0) {
        printf("\n");
        return 0;
     }
     for(int i = 0; i < len; i++)
     {
         dp[i][i] = 1;

     }

     memset(tag, -1, sizeof(tag));

     for(int i = len - 2; i >= 0; i--)
     {
         for(int j = i + 1; j < len; j++)
         {
             dp[i][j] = len + 1;
             if(match(str[i], str[j])) dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
             for(int k = i; k < j; k++)
             {
                 if(dp[i][j] > dp[i][k] + dp[k + 1][j])
                 {
                     dp[i][j] = dp[i][k] + dp[k + 1][j];
                     tag[i][j] = k;
                 }
             }
         }
     }


     print(0, len - 1);
     printf("\n");
}

猜你喜欢

转载自blog.csdn.net/deerly_/article/details/80342595
今日推荐