动态规划严格上不是一种算法,而是一种优化,用于去除重复计算。
看一道简单的题目:
现在有编码方式:A->'1',B->'2'……Z->'26',现给出一个数串,要求有几种译码方式?
动态规划考虑问题的基础是分解问题,所以一种提倡的方式就是先写递归形式,再转成递推。
而分解问题的要点是,不要执着于要一口气得到最终解。所谓分解问题,就是降模,也就是在考虑n规模的时候,先考虑n-1的规模。
此时我们假设i规模的问题已解决【先将解决方法当成黑盒】,然后考虑i+1的规模。
带入此题,假设我们已经求出前i个字符的划分方式,在考虑第i+1个字符的时候,如果把第i+1个字符当成是被划分出来的单个字符,那么dp[i+1]=dp[i]。第二种情况,上述最大被划分的数是26,最多两位,所以两位划分的情况是10~26,特判一下Ai和Ai+1是否能构成满足条件的数,满足则dp[i+1]还需要累加上dp[i-1]。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
int dp[100];
char tar[100];
int main(){
scanf("%s",tar+1);
dp[0]=0;
dp[1]=1;
int len=strlen(tar+1);
for(int i=2;i<=len;i++){
dp[i]=dp[i-1];//单字符划分
if((tar[i-1]=='1')||(tar[i-1]=='2')&&tar[i]<='6') {
dp[i]+=dp[i-2];
}
}
printf("%d",dp[len]);
}
不好意思上述代码有问题,现在给出修正代码:
修正1:字符串从索引1开始存储,前0个字符的划分方式是1,不是0。
修正2:字符长度为1的边界,直接打印1即可,不然在特判是否是两位中低位的时候会越界。
修正3:字符0,只能作为两位中的低位考虑,不能作为单字符划分,因此单字符的情况下的初始值为0而不是dp[i-1]。
#include<cstdio>
#include<cstring>
using namespace std;
int dp[100];
char tar[100];
int main(){
scanf("%s",tar+1);
dp[0]=1;
if(tar[1]=='0'){
printf("0");
return 0;
}
dp[1]=1;
int len=strlen(tar+1);
if(len==1){
printf("1");
return 0;
}
for(int i=2;i<=len;i++){
dp[i]=tar[i]=='0'?0:dp[i-1];//单字符划分
if((tar[i-1]=='1')||(tar[i-1]=='2'&&tar[i]<='6')) {
dp[i]+=dp[i-2];
}
}
printf("%d",dp[len]);
}