定义于字母表∑{a,b,c)上的乘法表如表1所示
表1∑乘法表
| a b c
--------
a| b b a
b| c b a
c| a c c
依此乘法表,对任一定义于∑上的字符串,适当加括号表达式后得到一个表达式。例如,对于字符串s[]=bbbba,它的一个加括号表达式为i
(b(bb))(ba)。依乘法表,该表达式的值为a。试设计一个动态规划算法,对任一定义于∑上的字符串s=s[1]x[2]…x[n],计算有多少种不同的加括号方式,使由x导出的加括号表达式的值为a
要求:
输入:输入一个以a,b,c组成的任意一个字符串。
输出:计算出的加括号方式数。
int 一个三位数组, s[100] 用来存 接收的字符串
用于记录一段连续的序列内通过加括号可得到a、b、c的方式数,
然后调用 递归程序 run(0,strlen(s)-1,need);(need 是 我们想要的结果)
,因为每两个字母相乘的结果已给出,所以可通过加和乘运算求出更大长度的字符串得到a、b、c的方式数
dp[i][j][s[need]] 表示 字符串s[i] s[i+1]....s[j]的表达式的值为s[need](s[need] 为
'a','b',或者'c'.) 的方式数;
递归式为:
(0 代表
'a' 1 代表
'b' 2 代表 'c' )
dp[s][t][0]
= dp[s][t][0] + run(s,i,0)*run(i+1,t,2) + run(s,i,1)*run(i+1,t,2) +
run(s,i,2)*run(i+1,t,0);
dp[s][t][1]
= dp[s][t][1] + run(s,i,0)*run(i+1,t,0) + run(s,i,0)*run(i+1,t,1) +
run(s,i,1)*run(i+1,t,1);
dp[s][t][2]
= dp[s][t][2] + run(s,i,1)*run(i+1,t,0) + run(s,i,2)*run(i+1,t,1) +
run(s,i,2)*run(i+1,t,2) ;
最初我吧 dp全部set 成 -1 这样便于记忆化搜索。。。避免重复递归。。。让递归跟递推一样快。
并且思路清楚
只要进来过 就 把 dp[s][t][need]=0; 应为有可能 s到t 值为need 的方法有0个 。
以下是我的程序
#include
#include
char s[100];
int n;
int dp[100][100][3];
int run(int s,int t,int need)
{
if(dp[s][t][need]!=-1)return dp[s][t][need];
int i;
dp[s][t][need]=0;
for(i=s;i
{
if(need==0)
dp[s][t][0]
= dp[s][t][0] + run(s,i,0)*run(i+1,t,2) + run(s,i,1)*run(i+1,t,2) +
run(s,i,2)*run(i+1,t,0);
else if(need==1)
dp[s][t][1]
= dp[s][t][1] + run(s,i,0)*run(i+1,t,0) + run(s,i,0)*run(i+1,t,1) +
run(s,i,1)*run(i+1,t,1);
else
dp[s][t][2]
= dp[s][t][2] + run(s,i,1)*run(i+1,t,0) + run(s,i,2)*run(i+1,t,1) +
run(s,i,2)*run(i+1,t,2) ;
}
return dp[s][t][need];
}
int main()
{
int i;
while(scanf("%s",&s)!=EOF)
{
memset(dp,-1,sizeof(dp));
n=strlen(s);
for(i=0;i
dp[i][i][s[i]-'a']=1;
printf("%dn",run(0,n-1,0));
}
return 0;
}