思路: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;
}
如有不当之处欢迎指出!