DP动态规划学习笔记
理解:
求当前状态的解,应该由子状态的解来得出,即:先必须求出子状态的解。一次往前递推,一般可由最最小的子问题(最易分析出结果,不可再分)逐层求出。
举个例子。
15=14+1;
14=13+1;
13=12+1;
......
2=1+1;
橙色的1期为之前提到的最最小的子问题。
分析:要求出15,可以分解成14+1;要求出14,可以分解成求出13,再加上1.
所以说先从最简单的2开始求。
一维DP问题:
最长非降子序列。
a[0] a[1] a[2] a[3] a[4] a[5] a[6]
5 3 4 8 7 9 3
d[i]表示以a[i]为结尾的最长非降子序列的长度。
d[0] = 1 序列:5
d[1] = 1 序列:3 因为5>3
d[2] = 2 序列:3 4
d[3] = 3 序列:3 4 8
........
不难得出,d[i]等于1(此时,a[i]的值比它前面任何一个数都小,所以只能a[i]它自己构成一个非降子序列)
或者是 max{ d[j]+1 } j的取值为:所有满足a[j]<=a[i]的j. 例:d[4]=max{ d[0]+1 ,d[1]+1 ,d[2]+1 }
代码:
1 //DP动态规划 最长非降子序列 2 #include<iostream> 3 using namespace std; 4 int main() 5 { 6 int a[100]; 7 int n; 8 cin>>n; 9 int i; 10 for(i=0;i<n;i++) 11 cin>>a[i]; 12 int d[n]; 13 d[0]=1; 14 int j; 15 for(i=1;i<n;i++) 16 { 17 d[i]=1; 18 for(j=i-1;j>=0;j--) 19 { 20 if(a[j]<=a[i]) 21 { 22 if(d[j]+1>d[i]) d[i]=d[j]+1; 23 } 24 } 25 cout<<i<<" "<<d[i]<<endl; 26 } 27 return 0; 28 }
二维DP问题:
平面上有m*n个格子,每个格子中放着一定数量的苹果。你从左上角的格子开始,每一步只能是向下走或是向右走,每次走到一个格子上就把格子里的苹果收集起来,这样下去最多能收集到多少个苹果。
1 //DP 苹果问题 2 #include<iostream> 3 using namespace std; 4 int main() 5 { 6 int a[100][100]; 7 int m,n,max; 8 cin>>m>>n; 9 int i,j,k; 10 for(i=0;i<m;i++) 11 { 12 for(j=0;j<n;j++) 13 cin>>a[i][j]; 14 } 15 int s[m][n]={0,0,0}; 16 for(i=0;i<m;i++) 17 { 18 for(j=0;j<n;j++) 19 { 20 21 if(i==0&&j==0) max=0; 22 else if(i>0&&j==0) max=s[i-1][j]; 23 else if(i==0&&j>0) max=s[i][j-1]; 24 else if(s[i-1][j]>s[i][j-1]) max=s[i-1][j]; 25 else max=s[i][j-1]; 26 s[i][j]=max+a[i][j]; 27 } 28 } 29 for(i=0;i<m;i++) 30 { 31 for(j=0;j<n;j++) 32 { 33 if(j==0) cout<<s[i][j]; 34 else cout<<" "<<s[i][j]; 35 } 36 cout<<endl; 37 } 38 }