https://yujia.io/blog/2015/10/31/SPOJ-SQRBR-Square%20Brackets/
Here valid means the way of filling the first elements should be the prefix of some valid matching. So by this definition, our goal is to calculate .
If is not in the sequence
http://www.cnblogs.com/huangfeihome/p/3420100.html
We are given:
- a positive integer ,
- an integer , ,
- an increasing sequence of integers .
And the output is the number of proper bracket expressions of length with opening brackets appering in positions .
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:
First we come up with the base case, if 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 the value of is exactly the value of . So we set
Now we need to find the relation on . There are two cases, if is in the sequence, which means we have to put “[“ in position , then should equal to . If is not in the sequence, then we can either put “[“ or “]” in position . So should equal to the sum of and . Note that cannot exceed because there are at most more “[“ than “]”. Also we can set . Formally, if is in the sequence
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 row by row, from left to right. The time complexity is and the space complexity is 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; }
动态规划。
设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 }