说明
留个纪念,记录部分大连理工大学算法设计与分析课程源代码。
本人代码水平有限,可能会有错误,请评论区交流讨论。
给学弟学妹一些方便,或者是有基础算法需求的朋友。编程语言c++。
本系列总目录
注意:参考书:王晓东《算法设计与分析第四版》
- 递归与分治算法
- 动态规划
- 贪心算法
- 回溯算法
本部分目录
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;
}