1. 程式人生 > >NYOJ15括號匹配

NYOJ15括號匹配

splay 長度 有一個 def can main nyist 一次 5%

NYOJ15括號匹配

括號匹配(二)

時間限制:1000 ms | 內存限制:65535 KB 難度:6
描述
給你一個字符串,裏面只包含"(",")","[","]"四種符號,請問你需要至少添加多少個括號才能使這些括號匹配起來。
如:
[]是匹配的
([])[]是匹配的
((]是不匹配的
([)]是不匹配的
輸入
第一行輸入一個正整數N,表示測試數據組數(N<=10)
每組測試數據都只有一行,是一個字符串S,S中只包含以上所說的四種字符,S的長度不超過100
輸出
對於每組測試數據都輸出一個正整數,表示最少需要添加的括號的數量。每組測試輸出占一行
樣例輸入
4
[]
([])[]
((]
([)]
樣例輸出
0
0
3
2
來源
《算法藝術與信息學競賽》

分析

二維數組dp[i][j] 表示字符串s的第i..j字符需要最少括號數,下面是具體的表示:

當i= j的時候,只有一個字符,那麽,只要匹配一個字符就行了,所以,dp[i][i] = 1

如果,當i < j的時候,s[i] = s[j] 那麽,dp[i][j] = min(dp[i][j],dp[i+1][j+1]),其中,假設i <= k < j 狀態轉移方程為 dp[i][j] = min(dp[i][j],d[i][k] + dp[k+1][j])

換個角度,換個方向

分析:我們求出這個串的最大匹配,然後串的總長度-最大匹配就是答案。

方法1:首先能想到的是轉化成LCS(最長公共子序列),枚舉中間點,求所有的LCS中的最大值 * 2就是最大匹配。但是復雜度較高,光LCS一次就O(n^2)的復雜度。

方法2:

首先考慮怎麽樣定義dp讓它滿足具有通過子結構來求解、

定義dp [ i ] [ j ] 為串中第 i 個到第 j 個括號的最大匹配數目

那麽我們假如知道了 i 到 j 區間的最大匹配,那麽i+1到 j+1區間的是不是就可以很簡單的得到。

那麽 假如第 i 個和第 j 個是一對匹配的括號那麽dp [ i ] [ j ] = dp [ i+1 ] [ j-1 ] + 2 ;

那麽我們只需要從小到大枚舉所有 i 和 j 中間的括號數目,然後滿足匹配就用上面式子dp,然後每次更新dp [ i ] [ j ]為最大值即可。

更新最大值的方法是枚舉 i 和 j 的中間值,然後讓 dp[ i ] [ j ] = max ( dp [ i ] [ j ] , dp [ i ] [ f ] + dp [ f+1 ] [ j ] ) ;

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 #define min(x,y) (x < y ? x : y)
 5 #define MAX 101
 6 
 7 int dp[MAX][MAX];
 8 
 9 bool cmp(int n,int m)
10 {
11     if((n == (&&m == ))||(n == [&&m == ]))
12     return 1;
13     else
14     return 0;
15 }
16 
17 int main(void)
18 {
19     int n,m,i,j,k;
20     char str[101];
21     scanf("%d",&n);
22     while(n--)
23     {
24         scanf("%s",str);
25         int length = strlen(str);
26         memset(dp,0,sizeof(dp));
27         for(i = 0; i < length; i++)
28         {
29             dp[i][i] = 1;
30         }
31         //區間dp常用dp套路 
32         for(m = 1; m < length; m++)//枚舉的串長度 
33         {
34             for(i = 0; i < length - m; i++)//起點 
35             {
36                 j = i + m;//終點 
37                 dp[i][j] = MAX; //初始值 
38                 if(cmp(str[i],str[j]))  
39                 dp[i][j] = min(dp[i][j],dp[i+1][j-1]);//消去匹配的括號
40                 //枚舉中間點 
41                 for(k = i; k < j; k++)
42                 {
43                    dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]);
44                 }
45             }
46         }
47         printf("%d\n",dp[0][length-1]);
48     }
49     return 0;
50 }

NYOJ15括號匹配