动态规划
动态规划的基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解,其经过分解的子问题往往不是相互独立的
- 其解依赖于子问题
- 子问题的求解是重复的
- 采用重递归出现的大量重复运算
如 Fib 数列
采用动态规划方法
- 构造所有子问题的一个表格
- 采用自底向上的方法依次求解子问题
- 也可以采用自上而下,为避免重复运算,采用 备忘录 或称为 记忆递归
F[1] = F[0] = 1;//最简单的子问题
for(int i = 2;i<=n;i++)
{
F[i] = F[i-1] + F[i-2];
}
//备忘录
long *F = new long[n+1];
//备忘录标志
for(int i = 0;i<=n;i++)
{
F[i] = 0;
}
long Fi(int n)
{
if(F(n)>0) return F[n];
if(n==0||n==1)
{
F[n] = 1;
return F[n];
}
return F[n-1]+F[n-2];
}
最长公共子序列
- 子序列 <X1,X3,X10> 是一个子序列
- 子串 Xi,Xi+1,Xi+2,Xi+3.....Xi+k
要找到 X = {x1,x2...xm } 和 Y= {y1,y2...yn} 的最长公共子序列
- 当 xi = yj 时,找到Xi-1和Yj-1的最长公共子序列,然后在尾部加上xi(yj)即可得X和Y的最长公共子序列。
- 当 xi != yj 时 找到Xi-1 和 Yj的最长子序列 和 Yj-1 和 Xi的最长子序列中的较大值
c[i][j] = 0 i=0,j=0
c[i][j] = c[i-1][j-1]+1 Xi= Yj
c[i][j] = max(c[i][j-1],c[i-1][j]) Xi != Yj
void LCSLength(int m,int n,char *x,char *y,int **c,int **b)
{
int i,j;
for( i = 1;i<=m;i++)//初始化
c[i][0] = 0;
for(i = 1;i<=n;i++)
c[0][i] = 0;
for(i = 1;i<=m;i++)
{
for(j = 1;j<=n;j++)
{
if(x[i]==y[j])
{
c[i][j] = c[i-1][j-1] + 1;
b[i][j] = 1;//标志位
}
else if(c[i-1][j]>=c[i][j-1])
{
c[i][j] = c[i-1][j];
b[i][j] = 2;
}
else
{
c[i][j] = c[i][j-1];
b[i][j] = 3;
}
}
}
}
//打印出最长公共子序列
void LCS(int i,int j,char *x,int **b)
{
if(i==0||j==0)
return ;
if(b[i][j]==1){
LCS(i-1,j-1,x,b);
cout<<x[i];
}
else if(b[i][j]==2)
LCS(i-1,j,x,b);
else
LCS(i,j-1,x,b);
}
and CJdl 代码送上
/*
二维数组的解法中的最优值二维数组 K 中,每一个K[i][j]的值仅与前一列、上一行、对角线的值有关
可将二维数组 K 压缩成一维数组 Z ,Z[j]对应 K[i][j];Z[0]存储 K[i][j]对角线的值,Z[j-1]对应 K[i][j]前一列值 K[i][j-1],Z[j]未改变前的值即对应 K[i][j]上一行的值K[i-1][j]
*/
int LCS(string X,string Y,int m,int n,string s[])
{
// Z 记录最优值,s 记录最优解
int Z[n+1];
for(int i=0;i<=n;i++)
{
Z[i]=0;
s[i]="";
}
for(int i=1;i<=m;i++)
{
//Z[0]暂存K[i][j]对角线位置的最优值,s[0]暂存对角线位置的最优解
Z[0]=0;
s[0]="";
for(int j=1;j<=n;j++)
{
if(X[i]==Y[j])
{
swap(s[j],s[0]);
swap(Z[j],Z[0]);
Z[j]++;
s[j]=s[j]+X[i];
}
else
{
Z[0]=Z[j];
s[0]=s[j];
if(Z[j]<Z[j-1])
{
Z[j]=Z[j-1];
s[j]=s[j-1];
}
}
}
}
return Z[n];
}
最大子段和
问题描述:给定由n个整数(可能为非负数)组成的序列a1,a2,a3,a4......an,求该序列的子段和的最大值.
动态规划核心更新公式:b[j] = max(b[j-1],0)+a[j]
int MaxSum(int n,vector<int> &a)
{
vector<int> b(0,a.size());
int sum = 0,b = 0;
for(int i = 1;i<n;i++)
{
b[i] = max(b[i-1],0) + a[i];
sum = max(sum,b[i]);
}
return sum;
}