动态规划
斐波那契数列
F【0】=1,F【1】=1 -> 边界条件
F【N】=F【N-1】+F【N-2】 -> 转移方程
F【0】、F【1】……F【N】 ->状态
书写代码方法:
顺着推/逆着推/记忆化搜索
代码示例:
#include<iostream> using namespace std; int n,f[10086]; int main(){ /* *顺着推 */ cin>>n; f[0]=1; f[1]=1; for( int i=2 ; i<=n ; ++i ){ f[i]=f[i-1]+f[i-2]; } cout<<f[n]; /* *逆着推 */ cin>>n; f[0]=1; f[1]=1; for( int i=0 ; i<n ; ++i ){ f[i-1] += f[i]; f[i-2] += f[i]; } cout<<f[n]; return 0; }
记忆化搜索:
#include<iostream> using namespace std; #define N 10086 int n; int f[N]; bool vis[N]; /* *搜索 */ int dfs( int n ){ if( n==0 ) return 1; if( n==1 ) return 1; return dfs(n-1)+dfs(n-2); }//O( f(n) ) /* *记忆化搜索 */ int dfs( int n ){ if( n==0 ) return 1; if( n==1 ) return 1; if( vis(n) ) return f[n]; vis[n] = 1; f[n] = dfs(n-1)+dfs(n-2); return f[n]; }//O(n) int main(){ cin>>n; cout<<dfs(n)<<endl; return 0; }
常见动态规划种类:
数位/树形/状压/区间/其他
(插头/博弈论)
数位DP:
读入两个正整数,L,R ,在【L,R】中,有多少个数?
[L~R] -> [0~R] - [0~(L-1)]
[0,X] -> Xn Xn-1 Xn-2 ...... Xn-n
0<=V<=X -> Vn Vn-1 Vn-2 ...... Vn-n
1、 XnXn-1Xn-2 > VnVn-1Vn-2 Vn∈[0,9];
2、 XnXn-1Xn-2 = VnVn-1Vn-2 Vn∈[0,Xn];
状态
f[i][j] -> 该状态方案数
i -> 已填好的第i位
j -> 0/1 j=0 XnXn-1Xn-2 > VnVn-1Vn-2
j=1 XnXn-1Xn-2 = VnVn-1Vn-2
转移方程
枚举i-1位填什么
f[i][j]=f[i-1][j]
边界
Xn+1 = 0 ; Vn+1 = 0
#include<iostream> using namespace std; #define N 10086 int l,r,z[N]; int f[N][2]; int solve( int x ){ int n=0; while(x){ z[n] = x%10; x/=10; n++; } n--; memset( f,0,sizeof(f)); f[n+1][1] = 1; for( int i=n ; i>=0 ; --i ){ for( int j=0 ; j<=1 ; ++j ){ if( b==0 ){ for( int k=0 ; k<=9 ; ++k ){ f[i][0] += f[i+1][0]; } } else{ for(int k=0 ; k<=z[a] ; ++k ){ if( k==z[a] ) f[a][1] += f[a+1][1]; else f[a][0] += f[a+1][1]; } } } } return f[0][0] + f[0][1]; } int main(){ cin>>l>>r; cout<< solve(r) - solve(l-1) <<endl; return 0; }