动态规划方法是集合的递推。
1、 最长单调递增子序列 LIS
给定10,4,20,10,15,13 序列(假设从第1项开始)。
确定状态:
以第i项结尾的最长单调递增子序列的长度为f(i)。
初始状态:f(0)=0; //因为没有第0项,因此以第0项结尾的最长递增子序列长度为0;
终止状态:max{f(1),f(2),f(3),…f(n)},其中值最大的就是最长的递增子序列长度;
决策: 已知第i项前的所有f(x),如果ai>ax,那么ai可以放在ax的后面。(要保存所有f(x))
总收益(公式):f(i)=max{f(x)|x<i && ai>ax}+1; 若集合中为空集,则max=0;
复杂度分析:
时间复杂度分析:需要遍历i(以第i项结尾的。。。)
需要遍历x,找到满足x<i && ai>ax的所有f(x)
因此时间复杂度为O(n^2)
空间复杂度分析:需要保存每个f(i),因此 为O(n)
记录决策:根据问题需要,记录对每个f(i)做出的决策x。
开始代码:
Int a[]={0,10,4,20,10,15,13};
Int f[100]={};
int n=sizeof(a)/sizeof(int);
Int max=0;
f(0)=1
bool flag=false;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[i]>a[j] && f[j]>=max){max=f[j]; flag =true;}
}
if(flag)
f[i]=max+1;
else f[i]=max;
//f[i]=max{f[j]| a[i]>a[j]}+1;
}
//最长子序列
//f[i]记录的是以第i个数作为子序列最后一个数的最长递增子序列。(注:第i个数为子序列的最后一个)
//子序列最长的需要从f[i]中遍历得到。
void main(){
int a[]={0,1,4,2,5,6,9,8,7,12,19,23,89,24,45,48,32};
int f[100]={0};
f[0]=1;
int n=sizeof(a)/sizeof(int);
//f[i]=max{f[x]| i>x && a[i]>a[x]}+1;
for(int i=1;i<n;i++){
f[i]=1;
for(int j=0;j<i;j++){
if(a[i]>a[j] && f[j]>=f[i])
f[i]=f[j]+1;
}
}
int max=0;
for(int i=0;i<n;i++){
cout<<' '<<f[i];
if(f[i]>max) max=f[i];
}
cout<<"\n max="<<max;
while (true)
{
}
}
//最长增长子序列
//f[i]记录的是以原序列中以第i个数结尾的最长递增子序列。(注:第i个数不一定在子序列中)
//因此,最大长度就是f[n-1]所记录的
void main(){
int a[]={0,1,4,2,5,6,9,8,7,12,19,23,89,24,45,48,32};
int f[100]={0};
f[0]=1;
int max=0;
int len=sizeof(a)/sizeof(int);
bool flag=false;
for(int i=1;i<len;i++){
for(int j=0;j<i;j++){
//f[i]=max{f[x]| i>x && a[i]>a[x]}+1;
if(a[i]>a[j]&& f[j]>=max){
max=f[j];
flag=true;
}
}
if(flag)
f[i]=max+1;
else f[i]=max;
flag=false;
max=f[i];
}
int i=0;
while(i<len){
cout<<" "<<f[i];
i++;
}
cout<<"\n max= "<<f[len-1];
while (true)
{
}
}