## Tuesday, September 20, 2016

### SPOJ-SQRBR: Square Brackets

https://yujia.io/blog/2015/10/31/SPOJ-SQRBR-Square%20Brackets/
We are given:
• a positive integer $n$,
• an integer $k$$1\le k\le n$,
• an increasing sequence of $k$ integers $0<{s}_{1}<{s}_{2}<\dots <{s}_{k}\le 2n$.
And the output is the number of proper bracket expressions of length $2n$ with opening brackets appering in positions ${s}_{1},{s}_{2},\dots ,{s}_{k}$.

I solve this problem by using dynamic programming. It’s not quite straighforward to come up with this idea. In dynamic programming, we are always trying to decompose the current state into some state that we have already solved before. Here I focus on the following function:
Here valid means the way of filling the first $i$ elements should be the prefix of some valid matching. So by this definition, our goal is to calculate $Opt\left(2n,0\right)$.

First we come up with the base case, if $i=1$ we have to put “[“ at the first place. That’s the only valid choice. If we put “]” at the first place then it won’t be the prefix of any valid matching. For $i>1$ the value of $OPT\left(i,0\right)$ is exactly the value of $OPT\left(i-1,1\right)$. So we set

Now we need to find the relation on $OPT\left(i,j\right)$. There are two cases, if $i$ is in the sequence, which means we have to put “[“ in position $i$, then $OPT\left(i,j\right)$ should equal to $OPT\left(i-1,j-1\right)$. If $i$ is not in the sequence, then we can either put “[“ or “]” in position $i$. So $OPT\left(i,j\right)$ should equal to the sum of $OPT\left(i-1,j-1\right)$ and $OPT\left(i-1,j+1\right)$. Note that $j+1$ cannot exceed $n$ because there are at most $n$ more “[“ than “]”. Also we can set $OPT\left(i,n+1\right)=0$. Formally, if $i$ is in the sequence
$OPT\left(i,j\right)=OPT\left(i-1,j-1\right)$
If $i$ is not in the sequence

$OPT\left(i,j\right)=OPT\left(i-1,j-1\right)+OPT\left(i-1,j+1\right)$

I construct the following table. By the base case, we can calculate the frist row. And then by the recurrent relations, we calculate the value of $OPT\left(i,j\right)$ row by row, from left to right. The time complexity is $O\left({n}^{2}\right)$ and the space complexity is $O\left(n\right)$ because we only need the previous row to calculate the current row. We don’t need to store the whole table.
int main(){
int T;
cin >> T;
int result[10];
for(int t = 0; t < T; t++){
int s[19];
int n,k;
cin >> n >> k;
for(int i = 0; i < k; i++)
cin >> s[i];
int Previous[20];
int Current[20];
for(int j = 0; j <= n; j++)
Previous[j] = 0;
Previous[1] = 1;
int position = (s[0] == 1) ? k-1 : k;
for(int i = 2; i <= 2*n; i++){
if((position > 0) && (s[k-position] == i)){
position--;
Current[0] = 0;
for(int j = 1; j <= n; j++)
Current[j] = Previous[j-1];
}else{
Current[0] = Previous[1];
for(int j = 1; j < n; j++)
Current[j] = Previous[j-1] + Previous[j+1];
Current[n] = Previous[n-1];
}
for(int j = 0; j <= n; j++)
Previous[j] = Current[j];
}
result[t] = Previous[0];
}
for(int t = 0; t < T; t++)
cout << result[t] << endl;
}
http://www.cnblogs.com/huangfeihome/p/3420100.html
动态规划。
设f[i][j]表示前i个位置在合法情况下缺少j个右括号的方案数。
转移方程为：
f[i][j] = f[i-1][j-1] (第i个地方必须为'[')
f[i][j] = f[i-1][j-1] + f[i-1][j+1] (分第i个位置放左括号和右括号的情况)
写的第一份代码不是很严谨，j-1变为负值，但spoj判ac了。
 3 #define N 205
4
5 int f[N][N], n, k;
6 bool h[N];
7
8 int main()
9 {
10     int t, d;
11     scanf("%d", &t);
12     while(t--)
13     {
14         scanf("%d%d", &n, &k);
15         memset(h, 0, sizeof h);
16         memset(f, 0, sizeof f);
17         f[0][0] = 1;
18         for(int i = 1; i <= k; i++)
19         {
20             scanf("%d", &d);
21             h[d] = 1;
22         }
23         for(int i = 1; i <= 2 * n; i++)
24         {
25             for(int j = 0; j <= 2 * n; j++)
26             {
27                 if(h[i])
28                 {
29                     if(j != 0)
30                         f[i][j] = f[i-1][j-1];
31                     else
32                         f[i][j] =  0;
33                 }
34                 else
35                 {
36                     if(j != 0)
37                         f[i][j] = f[i-1][j-1] + f[i-1][j+1];
38                     else
39                         f[i][j] = f[i-1][j+1];
40                 }
41             }
42         }
43         printf("%d\n", f[2*n][0]);
44     }
45     return 0;
46 }