思路:dp(i)表示前i个字符的解码方案种数。进行状态转移时需要仔细思考,分情况讨论:
设第i个字符和第i-1个字符组成的数为x。
1.如果x根本不可能出现说明不是合理的编码,直接使dp(i)为0,例如00,50,30等
2.如果x<10 || x>26,说明第i个字符一定不能和第i-1个字符组成一个字母,那么dp(i) = dp(i-1);
3.如果x == 20 || x == 10,说明第i个字符一定只能和第i-1个字符组成一个字母,那么dp(i) = dp(i-2);
4.(x>10 || x <= 26) && x != 20,说明第i个字符可以和第i-1个字符组成一个字母,也可以单独成为一个字母,那么dp(i)
= dp(i-1) + dp(i-2);
AC代码:
#include <cstdio> #include <cmath> #include <cctype> #include <algorithm> #include <cstring> #include <utility> #include <string> #include <iostream> #include <map> #include <set> #include <vector> #include <queue> #include <stack> using namespace std; #pragma comment(linker, "/STACK:1024000000,1024000000") #define eps 1e-10 #define inf 0x3f3f3f3f #define PI pair<int, int> typedef long long LL; const int maxn = 1e4 + 5; char s[maxn]; int dp[maxn]; int main() { while(scanf("%s", s+1) == 1) { int n = strlen(s+1); memset(dp, 0, sizeof(dp)); dp[0] = 1; if(s[1] == '0') dp[1] = 0; else dp[1] = 1; for(int i = 2; i <= n; ++i) { if(s[i] == '0' && (s[i-1] > '2' || s[i-1] == '0')) continue; int x = (s[i-1]-'0')*10 + s[i]-'0'; if(x == 10 || x == 20) { dp[i] = dp[i-2]; } else if(x < 10 || x > 26) { dp[i] = dp[i-1]; } else { dp[i] = dp[i-1] + dp[i-2]; } } printf("%d\n", dp[n]); } return 0; }
如有不当之处欢迎指出!