1. 程式人生 > >括號匹配 (區間dp)

括號匹配 (區間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");
}

相關推薦

括號匹配 區間dp

區間dp 題目大意:給出一個的只有’(‘,’)’,’[‘,’]’四種括號組成的字串,求最多有多少個括號滿足匹配。 題目連結 思路:用dp[i][j]表示區間i~j的最大匹配數,對於dp[i][j] = dp[i + 1][j - 1] + (s[i]和s[

括號匹配問題區間dp

最小值 很好 nbsp 需要 簡單的 棧模擬 pri tex 什麽 簡單的檢查括號是否配對正確使用的是棧模擬,這個不必再說,現在將這個問題改變一下:如果給出一個括號序列,問需要把他補全成合法最少需要多少步? 這是一個區間dp問題,我們可以利用區間dp來解決,直接看代碼吧!

括號匹配區間dp

括號匹配(二)題目描述:給你一個字串,裡面只包含"(",")","[","]"四種符號,請問你需要至少新增多少個括號才能使這些括號匹配起來。如:[]是匹配的([])[]是匹配的((]是不匹配的([)]是

nyoj 15 括號匹配區間DP

括號匹配(二) 描述 給你一個字串,裡面只包含"(",")","[","]"四種符號,請問你需要至少新增多少個括號才能使這些括號匹配起來。 如: []是匹配的 ([])[]是匹配的 ((]是不匹

LightOJ - 1422 Halloween Costumes 區間DP

wan things strong cas book article printf ase con Description Gappu has a very busy weekend ahead of him. Because, next weekend is Ha

POJ 1141 Brackets Sequence 區間DP

ive bsp rip mes character har typedef som memset Description Let us define a regular brackets sequence in the following way: 1.

Brackets Sequence POJ - 1141 區間dp

gif == urn ++ char img ems utc pre Brackets Sequence POJ - 1141 題意:給一個括號序列,問最少添加多少個括號似的原序列匹配,並輸出新序列。 用dp[i][j]表示i到j最少添加幾個括號,flag[i][j]表

Brackets POJ - 2955 區間dp

pla clu for eof %d img rac end racket Brackets POJ - 2955 題意:給一個括號序列,問最多有多少個括號是可以配對的。 1 #include<cstdio> 2 #include<algori

Food Delivery ZOJ - 3469 區間dp

位置 turn pro pan return isp ive != truct Food Delivery ZOJ - 3469 題意:快遞員送外賣,n個客戶,起始位置為x,速度為v,每個客戶單位時間不滿意度增加hi,問最少增加多少不滿意度。 每一個客戶可能是從左側送到

CSUOJ-1980 不堪重負的數區間dp

inline 滿二叉樹 -a ems ext div des button problems 1980: 不堪重負的樹 Submit Page Summary Time Limit: 1 Sec Memory Limit: 128 Mb Subm

POJ 1991 Turning in Homework區間DP

clu sin highlight sort stream ret spa 作業 ref 題目鏈接 Turning in Homework 考慮區間DP f[i][j][0]為只考慮區間[i, j]且最後在a[i]位置交作業的答案。 f[i][j][1]為只考慮區間[

hdu6212 祖瑪區間DP

tro 位置 表示 中間 ron i+1 strong 就會 題意 題意   有一個長度為n的01串,我們可以在某個地方插入一個0或者1,那麽如果有連續顏色相同的>=3個,那麽這段就會消去,兩邊的合攏。問將所有01串消去,最少需要插入多少個。(n<=200)

修長城 區間DP

urn ret 世紀 log width hide 時間 main gif Time Limit: 1000 ms Memory Limit: 256 MB Description   大家都知道,長城在自然條件下會被侵蝕,因此,我們需要修復。現在是21世紀,

Codeforces 392E Deleting Substrin區間dp

read temp put tdi char i+1 void log ++ 題目大意: ? 給定vi,wi,每次可以在wi中選擇一個子段[l,r]滿足:? |wi-wi+1|=1 (l<=i<r)? 2wi-wi-1-wi+1>=0 (l<i<

【Uva10559】Blocks區間DP

log turn logs efi read etc body pre 數量 Description 題意:有一排數量為N的方塊,每次可以把連續的相同顏色的區間消除,得到分數為區間長度的平方,然後左右兩邊連在一起,問最大分數為多少。 \(1\leq N\leq200\) S

You Are the One HDU - 4283區間dp

eas value script names elf for stdio.h 表示 text You Are the One Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav

Topcoder SRM 301 Div2-1000 CorrectingParenthesization區間DP

完全 errors 實現 括號 cor ren opc fin 區間dp 題意 給定一個長度為偶數的字符串。這個字符串由三種括號組成。    現在要把這個字符串修改為一個符合括號完全匹配的字符串,改變一個括號的代價為$1$,求最小總代價。 區間DP。令$dp[i

【BZOJ】1260 [CQOI2007]塗色paint區間dp

c++ ide hid event pri display pro == spl 題目 傳送門:QWQ 分析 區間dp, 詳見代碼 代碼 /*****************************************

【lightoj-1025】The Specials Menu區間DP

.com lightoj 不同 cin mes std 需要 就是 ++ 題目鏈接:http://www.lightoj.com/volume_showproblem.php?problem=1025 【題目大意】 求一個字符串刪去任意字符可以構成多少個不同的回文

POJ 1651 Multiplication Puzzle 區間DP

contain 個數 ++ %d str poi point return IE Description The multiplication puzzle is