問題:
定義於字母表∑{a,b,c)上的乘法表如表所示:
依此乘法表,對任一定義於∑上的字符串,適當加括號表達式后得到一個表達式。
例如,對於字符串x=bbbba,它的一個加括號表達式為(b(bb))(ba)。依乘法表,該表達式的值為a。
試設計一個動態規划算法,對任一定義於∑上的字符串x=x1x2…xn,計算有多少種不同的加括號方式,使由x導出的加括號表達式的值為a。
輸入:
輸入一個以a,b,c組成的任意一個字符串 str。
輸出:
計算出的加括號方式數。
分析:
設常量a,b,c 分別為 1, 2 ,3 。n 為字符串的長度。
設字符串的第 i 到 第 j 位乘積為 a 的加括號法有 result[i][j][a] 種,
字符串的第 i 到 第 j 位乘積為 b 的加括號法有 result[i][j][b] 種,
字符串的第 i 到 第 j 位乘積為 c 的加括號法有 result[i][j][c] 種。
則原問題的解是: result[i][n][a] 。
設 k 為 i 到 j 中的某一個字符,則對於 k 從 i 到 j :
result[i][j][a] += result[i][k][a] * result[k + 1][j][c] + result[i][k][b] * result[k + 1][j][c] + result[i][k][c] * result[k + 1][j][a];
result[i][j][b] += result[i][k][a] * result[k + 1][j][a] + result[i][k][a] * result[k + 1][j][b] + result[i][k][b] * result[k + 1][j][b]; result[i][j][c] += result[i][k][b] * result[k + 1][j][a] + result[i][k][c] * result[k + 1][j][b] + result[i][k][c] * result[k + 1][j][c];

算法思路:
初始化
for (int i = 1; i <= n; i++) { //初始化 result[i][i][a] = (str[i-1] == 'a' ? 1 : 0); result[i][i][b] = (str[i-1] == 'b' ? 1 : 0); result[i][i][c] = (str[i-1] == 'c' ? 1 : 0); }
接着從長度為 2 的子字符串計算,直至計算好整串 str 。
計算順序:

for (int r = 2; r <= n; r++)
{//接着從長度為 2 的子字符串計算,直至計算好整串 str for (int i = 1; i <= n; i++) { int j = i + r - 1;//計算str[i:j] for (int k = i; k <= j; k++) {//根據題目中的表,計算加括號法 result[i][j][a] += result[i][k][a] * result[k + 1][j][c] + result[i][k][b] * result[k + 1][j][c] + result[i][k][c] * result[k + 1][j][a]; result[i][j][b] += result[i][k][a] * result[k + 1][j][a] + result[i][k][a] * result[k + 1][j][b] + result[i][k][b] * result[k + 1][j][b]; result[i][j][c] += result[i][k][b] * result[k + 1][j][a] + result[i][k][c] * result[k + 1][j][b] + result[i][k][c] * result[k + 1][j][c]; } } }
輸出結果:
cout << result[1][n][a] << endl;