poj1141 动态规划

来源:互联网 发布:去除图片马赛克软件 编辑:程序博客网 时间:2024/06/05 09:29
题意:定义了regular brackets sequence,即满足以下条件:

1、空串是regular brackets sequence

2、如果S是regular brackets sequence,则[S]和(S)也是regular brackets sequence

3、如果A、B都是regular brackets sequence,则AB也是regular brackets sequence

一些regular brackets sequence例子

(), [], (()), ([]), ()[], ()[()] 

一些非regular brackets sequence例子

(, [, ), )(, ([)], ([(]

问题:现在给出一个序列,要你通过添加括号来将给出的序列变成regular brackets sequence

样例

Sample Input

([(]

Sample Output

()[()]

题解:这题乍看时没啥思路,虽然自己是最近在练习动态规划,但是不知道怎么往dp上想,自己思维能力太菜了,o(︶︿︶)o 唉!!!没辙,网上找题解,一看自己傻眼了,这么容易的dp式子自己就是想不到,脑子这硬伤如何修复啊T_T

其实这题的动态转移方程和常规,设置一个dp[i,j]表示从第i个字符到第j个字符要形成一个regular brackets sequence需要添加的最少字符数(想了想,自己之所以没想到这个状态表示是因为被题目给迷惑,老想着怎么添加括号,没想着关键因素:添加最少的括号数。其实如果知道一个区间内最少需要添加的括号数,具体怎么添加也就不在话下了,有点事后诸葛的意思:))

好了,表示好了状态之后,就需求如何进行状态转移

我们可以将区间就行划分,然后要使总区间的括号数最少,就得选择一个划分状态,使得划分开的两边最少括号数之和最小,这里需要用到一点分治的思路,大问题通过划分成几个小问题来求解,其实动态规划也就是一种可以解决分治算法重复求解某些状态的方法。

①dp[i,j] = min{dp[i,k] + dp[k+1,j]} (i<=k<j)

这里需要注意,上面的状态转移方程还有一种情况没有考虑,就是当i和j正好是一对匹配括号时,我们需要另外设置一个状态转移方程②dp[i,j] = dp[i+1,j-1]。

做到这里我又有点想当然了,认为如何满足条件②的话,就不必再求条件①,这是一种很不严谨的思路,我们找不到任何方法说明它是正确的,反而可以找到一组反例,假设给出的序列是()(),如果用这种思路的话,肯定需要添加的最少括号数为2,输出的结果是()()()。所以以后碰到类似情况的时候,除非确定某些情况是最优的,不然一定要所有情况都进行比较取最优。

下面贴下代码

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. #define N 101  
  5. #define INF 0x7fffffff  
  6.   
  7. char Brackets[N];  
  8. int dp[N][N];  
  9. int path[N][N];  
  10.   
  11. bool Match(char a, char b)  
  12. {  
  13.     if ((a == '[' && b == ']') || (a == '(' && b == ')'))  
  14.         return 1;  
  15.     return 0;  
  16. }  
  17.   
  18. void PrintBracket(char c)  
  19. {  
  20.     if (c == '[' || c == ']')  
  21.         printf("[]");  
  22.     else if (c == '(' || c == ')')  
  23.         printf("()");  
  24. }  
  25.   
  26. void PrintPath(int l, int r)  
  27. {  
  28.     if (l > r)  
  29.         return;  
  30.     if (l == r)  
  31.         PrintBracket(Brackets[l-1]);  
  32.     else  
  33.     {  
  34.         if (path[l][r] == -1)  
  35.         {  
  36.             printf("%c", Brackets[l-1]);  
  37.             PrintPath(l+1, r-1);  
  38.             printf("%c", Brackets[r-1]);  
  39.         }  
  40.         else  
  41.         {  
  42.             PrintPath(l, path[l][r]);  
  43.             PrintPath(path[l][r] + 1, r);  
  44.         }  
  45.     }  
  46. }  
  47.   
  48. void MinLenSubSeq()  
  49. {  
  50.     int i;  
  51.     int j;  
  52.     int k;  
  53.     int len = strlen(Brackets);  
  54.     for (i = 1; i <= len; i++)  
  55.     {  
  56.         dp[i][i] = 1;  
  57.         dp[i][i-1] = 0;  
  58.     }  
  59.     memset(path, -1, sizeof(path));  
  60.   
  61.     for (k = 1; k < len; k++)  
  62.     {  
  63.         for (i = 1; i + k <= len; i++)  
  64.         {  
  65.             j = i + k;  
  66.             int t;  
  67.             dp[i][j] = INF;  
  68.             for (t = i; t < j; t++)  
  69.             {  
  70.                 int bracket_num = dp[i][t] + dp[t+1][j];  
  71.                 if (bracket_num < dp[i][j])  
  72.                 {  
  73.                     dp[i][j] = bracket_num;  
  74.                     path[i][j] = t;  
  75.                 }  
  76.             }  
  77.             if (Match(Brackets[i-1], Brackets[j-1]) && dp[i+1][j-1] < dp[i][j])  
  78.             {  
  79.                 dp[i][j] = dp[i+1][j-1];  
  80.                 path[i][j] = -1;  
  81.             }  
  82.         }  
  83.     }  
  84.     //printf("minimal possible length is %d\n", dp[1][len]);  
  85.     PrintPath(1, len);  
  86.     printf("\n");  
  87. }  
  88.   
  89. int main(void)  
  90. {  
  91.     int i;  
  92.     while (gets(Brackets))  
  93.     {  
  94.         MinLenSubSeq();  
  95.     }  
  96.   
  97.     return 0;  
  98. }  
原创粉丝点击