这个周主要看了动态规划DP,DP题目类型比较多,没有固定模版。
题目类型有:求最长上升序列、最小正数子段和、最长公共子序列、求从一个地方到另一个地方经过权值和最大或最小,选出k个数使得和是sum的方法数,从一个地方到另一个地方的方法数。
动态规划比一般的枚举递归好在了把已经计算出来的结果保存起来,后面还需要使用的话可以直接用,不用重复计算,降低了时间复杂度。
下面是求最长上升序列的状态转移方程模版:导弹拦截(二分之一➕线性DP)
for(int i=2;i<=n+1;i++)
{
int num=0;
for(int j=i-1;j>=1;j--)
if(a[i]>a[j])
num=max(num,dp[j]);//dpi表示ai结尾的最长上升子序列的长度
dp[i]=num+1;
}
求最长上升公共子序列状态转移方程模版:
char s[MAX],t[MAX];
scanf("%s%s",s,t);
int x=strlen(s),y=strlen(t);
for(i=0;i<x;i++)
{
for(j=0;j<y;j++)
{
if(s[i]==t[j])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
}
printf("%d\n",dp[i][j]);
}
最大矩阵和动态转移方程模版:https://www.luogu.com.cn/problem/P1508
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int temp;
scanf("%d",&temp);
a[i][j]=a[i-1][j]+t;
}
}
int ans=-INF;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
int sum=0;
for(int k=1;k<=m;k++){
sum=sum+(a[j][k]-a[i-1][k]);
if(sum<0)
sum=0;
if(sum>ans)
ans=sum;
}
}
}