算法设计与分析基础2 动态规划

说明

留个纪念,记录部分大连理工大学算法设计与分析课程源代码。
本人代码水平有限,可能会有错误,请评论区交流讨论。
给学弟学妹一些方便,或者是有基础算法需求的朋友。编程语言c++。

本系列总目录

注意:参考书:王晓东《算法设计与分析第四版》

  1. 递归与分治算法
  2. 动态规划
  3. 贪心算法
  4. 回溯算法

本部分目录

1.动态规划理解

动态规划的特征是最优子结构与重叠子问题。

最优子结构性质:原问题的最优解包含着子问题的最优解,换句话说最后的最优解是用子问题的最优解来表示的。

动态规划的一般步骤为:
1.找出最优解的性质并刻画其特征(定义变量)
2.递归的定义最优值(写状态转移方程)
3.自底向上的计算最优值(定义好初始值后从头开始迭代执行状态转移方程)

2.动规:01背包问题

/*
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
*/ 
#include<iostream>
#include<algorithm>
using namespace std;

const int N=1010;
int f[N][N];
int v[N];
int w[N];

int main()
{
    int n,m;
    cin>>n>>m;//n件物品,背包容量为m
    
    for(int i=1;i<=n;i++)
    {
        cin>>v[i]>>w[i];
    }
    
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            
            if(j>=v[i])
            {
                f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
            }
        }
    }
    
    cout<<f[n][m];
    return 0;
}

3.动规:最大子段和

//给一个整数数组,你可以在上面随意连续的截取一部分,求这个部分的最大和 
/*
输入一个 非空 整型数组,数组里的数可能为正,也可能为负。
数组中一个或连续的多个整数组成一个子数组。
求所有子数组的和的最大值。
要求时间复杂度为O(n)。

*/
#include<iostream>
#include<algorithm>
using namespace std;

const int N=1010;
int a[N];

int maxSub(int a[],int n)
{
	int sum=a[0];
	int curmax=0;
	for(int i=0;i<n;i++)
	{
		if(curmax>0) curmax+=a[i];
		else
		{
			curmax=a[i];
		}
		
		if(curmax>sum) sum=curmax;
	}
	return sum;
}

int main()
{
    int n;
    for(int i=0;i<n;i++)
    {
    	cin>>a[i];
	 } 
	 
	cout<<=maxSub(a,n);
    return 0;
}

4.动规:最大子矩阵和

//最大子段和的推广 :应用于二维 

#include <iostream>
using namespace std;

int maxSubArray(int a[],int n)//封装好求一维最大子列和的函数 
{ 
     int b=0,sum=a[0];
     for(int i=0;i<n;i++)
     {
       if(b>0) 
          b+=a[i];
       else 
          b=a[i];
       if(b>sum)
          sum=b;
     }
    return sum;  
}

int maxSubMatrix(int array[][3],int n)
{
            int i,j,k,max=0,sum=-100000000;
            int b[3];
            for(i=0;i<n;i++)//遍历一遍整个二维矩阵 
            {
                  for(k=0;k<n;k++)//初始化b[]
                  {
                        b[k]=0;
                  }
                  
                  for(j=i;j<n;j++)//把第i行到第j行相加,对每一次相加求出最大值
                  {
                        for(k=0;k<n;k++)
                        {
                            b[k]+=array[j][k];
                        }
                        
                        max=maxSubArray(b,k);  
                        
                        if(max>sum)
                        {
                            sum=max;
                        }
                  }
            }
            return sum;
}
int main()
{ 
    int n=3;
    int array[3][3]={{1,2,3},{-1,-2,-3},{4,5,6}};//为了方便直接这样初始化 
                      
    cout<<"MaxSum: "<<maxSubMatrix(array,n)<<endl;
            
 }

5.动规:最长公共子序列问题

// An highlighted block
//最长公共子序列问题 
//动态规划的特征:最优子结构与重叠子问题 
//动态规划步骤:
/*
1. 找出最优解的性质刻画其结构特征(定义变量) 
2.递归的定义最优值(写状态转移方程) 
3.自底向上的方式计算最优值 (初始化边界,执行状态转移方程) 

*/ 
#include<iostream>
#include<algorithm>
using namespace std;

const int N=1010;
int f[N][N];//表示在n位置的最长子序列长度
char a[N],b[N];

int main()
{
    int a_length,b_length;
    cin>>a_length>>b_length;
    
    for(int i=1;i<=a_length;i++) cin>>a[i];
    for(int i=1;i<=b_length;i++) cin>>b[i];
    
    for(int i=1;i<=a_length;i++)
    {
    	for(int j=1;j<=b_length;j++)
    	{
    		if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
    		else 
    		{
    			f[i][j]=max(f[i-1][j],f[i][j-1]);
			}
		}
	}
	  
    cout<<f[a_length][b_length];
    return 0;
}

6.动规:最长上升子序列

#include<iostream>
#include<algorithm>
using namespace std;

const int N=1010;
int f[N];//表示在n位置的最长子序列长度
int t[N];

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>t[i];
    }
    
    for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<=i-1;j++)
        {
            
            if(t[i]>t[j]) f[i]=max(f[i],f[j]+1);
        }
    }
    
    int res=0;
    for(int i=1;i<=n;i++)
    {
        res=max(res,f[i]);
    }
    cout<<res;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值