zoj 3171 The Hidden 7's
这道题,我在网上看到两种dp,不过基本原理是一样的,不过感觉还是后面的一种比较巧妙!因为我对动态不是很熟,自能加上一些自己的理解,写上注释。
1)
#include <stdio.h> #include <string.h> #include<ctype.h> char str[10003]; long long int dp[6][10003]; /*2^63次恰好是longlong int */ int main(void) { long long int i,j,len; while(scanf("%s",str) != EOF) { memset(dp,0,sizeof(dp)); len = strlen(str); for (i = 0;i<len;i++)/*转化为小写字母*/ str[i]=tolower(str[i]); if(str[0] == 's') dp[0][0] = 1; /*dp[j][i] 第i个位置上第j个字母的数量与前面字母交叉匹配的数量;*/ for(i=1;i<len;i++) { for(j=0;j<5;j++)/*第i个位置肯不是四个,但是我们要计算个数,那么i个位置无论有没有出现过这个字母都继承前面的 */ dp[j][i]=dp[j][i-1]; if(str[i] == 's')/*统计s的数量*/ dp[0][i]++; if(str[i] == 'e')/*每次后面的字母匹配数就加上与之前字母匹配的个数*/ { dp[1][i]+=dp[0][i-1]; dp[3][i]+=dp[2][i-1]; } else if(str[i] == 'v') dp[2][i] += dp[1][i-1]; else if(str[i] == 'n') dp[4][i]+=dp[3][i-1]; } printf("%lld\n",dp[4][len-1]);/*最后一个位置最后一个字母与倒数第二个字母交叉匹配的数量即最后seven隐含的总个数 */ } return 0; }
2)
#include<stdio.h> #include<string.h> #include<ctype.h> char str[10010]; long long unsigned dp[6]; int main(void) { int i,j; char seven[]=" seven"; while(scanf("%s",str) != EOF) { memset(dp,0,sizeof(dp)); dp[0]=1; for( i=0;str[i];++i) { str[i]=tolower(str[i]); /*dp[j]表示到达seven[j]有多少条路径。如果str[i]和seven[j]相等, 则dp[j]就多出dp[j-1]条路径。类似于01背包,因为str中的每个字符只能取一次,所以要从后往前遍历。 */ for( j=5;j>0;--j) if(str[i]==seven[j]) dp[j]=dp[j-1]+dp[j]; /*原理基本和上面代码一样, 都是遇到一个字母就将该字母的匹配数加上前面字母的匹配数 ,对seven字母的比较,不过上面的是顺下来,这个倒回去*/ } printf("%llu\n",dp[5]); } return 0; }