动态规划_线性动态规划,区间动态规划
Posted 一只特立独行的猫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划_线性动态规划,区间动态规划相关的知识,希望对你有一定的参考价值。
模板题链接:
线性规划
数字三角形
思路:
状态表示:
a
r
r
[
i
]
[
j
]
arr[i][j]
arr[i][j]表示从(1,1)出发到(i,j)的最长路径。
状态表示:
a
r
r
[
i
]
[
j
]
=
m
a
x
(
a
r
r
[
i
−
1
]
[
j
−
1
]
,
a
r
r
[
i
−
1
]
[
j
]
)
+
a
r
r
[
i
]
[
j
]
arr[i][j]=max(arr[i-1][j-1],arr[i-1][j])+arr[i][j]
arr[i][j]=max(arr[i−1][j−1],arr[i−1][j])+arr[i][j]
代码:
#include<iostream>
using namespace std;
const int N = 505,INF=1e9;
int arr[N][N];
int main(){
int n;
cin>>n;
for(int i=0;i<=n;i++){//初始化
for(int j=0;j<=n;j++){
arr[i][j]=-INF;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>arr[i][j];
}
}
for(int i=2;i<=n;i++){//状态转移
for(int j=1;j<=i;j++){
arr[i][j]+=max(arr[i-1][j-1],arr[i-1][j]);
}
}
int res=-INF;
for(int i=1;i<=n;i++) res=max(res,arr[n][i]);
cout<<res<<endl;
return 0;
}
最长上升子序列:
思路:
状态表示:
f
[
i
]
f[i]
f[i]表示以i号数字结尾的最长公共自序列长度。
状态表示:
f
[
i
]
=
m
a
x
{
f
[
j
]
+
1
∣
j
∈
{
j
∣
a
[
j
]
<
a
[
i
]
}
}
f[i]=max\\{f[j]+1|j∈\\{j|a[j]<a[i]\\}\\}
f[i]=max{f[j]+1∣j∈{j∣a[j]<a[i]}}
代码:
#include<iostream>
using namespace std;
const int N = 1005;
int a[N],f[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
f[i]=1;
for(int j=1;j<i;j++){
if(a[j]<a[i]){
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<<endl;
return 0;
}
最长公共子序列
思路:
状态表示:
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示a字符串的前i个字符和b字符串的前j个字符的最长公共自序列。
状态表示:
f
[
i
]
[
j
]
=
m
a
x
{
f
[
i
−
1
]
[
j
−
1
]
,
f
[
i
−
1
]
[
j
]
,
f
[
i
]
[
j
−
1
]
,
f
[
i
−
1
]
[
j
−
1
]
+
1
}
f[i][j]=max\\{f[i-1][j-1],f[i-1][j],f[i][j-1],f[i-1][j-1]+1\\}
f[i][j]=max{f[i−1][j−1],f[i−1][j],f[i][j−1],f[i−1][j−1]+1}
分别表示不包括i和j位字符,选包括j位字符,包括i位字符,包括i位和j位字符。
代码:
#include<iostream>
using namespace std;
const int N = 1e3+5;
int n,m,f[N][N];
char a[N],b[N];
int main(){
int res=0;
scanf("%d%d",&n,&m);
scanf("%s%s",a+1,b+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=max(f[i][j-1],f[i-1][j]);
if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
}
}
cout<<f[n][m]<<endl;
return 0;
}
区间动态规划
石子合并
思路:
状态表示:
f
[
l
]
[
r
]
f[l][r]
f[l][r]表示合并从i到j区间的石子的最小代价。
状态表示:
f
[
l
]
[
r
]
=
m
i
n
{
f
[
l
]
[
k
]
+
f
[
k
+
1
]
[
r
]
+
s
u
m
(
a
[
l
]
,
.
.
.
,
a
[
r
]
)
}
,
k
∈
[
l
,
r
−
1
]
f[l][r]=min\\{f[l][k]+f[k+1][r]+sum(a[l],...,a[r])\\},k∈[l,r-1]
f[l][r]=min{f[l][k]+f[k+1][r]+sum(a[l],...,a[r])},k∈[l,r−1]
一般区间长度从小到大循环。
代码:
#include<iostream>
#include<cstring>
using namespace std;
const int N = 305;
int a[N],f[N][N],s[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int l=i,r=i+len-1;
f[l][r]=1e8;
for(int j=l;j<r;j++){
f[l][r]=min(f[l][r],f[l][j]+f[j+1][r]+s[r]-s[l-1]);
}
}
}
cout<<f[1][n]<<endl;
return 0;
}
以上是关于动态规划_线性动态规划,区间动态规划的主要内容,如果未能解决你的问题,请参考以下文章
ACM - 动态规划小白入门:背包 / 线性 / 区间 / 计数 / 数位统计 / 状压 / 树形 / 记忆化 DP
算法动态规划 ④ ( 动态规划分类 | 坐标型动态规划 | 前缀划分型动态规划 | 前缀匹配型动态规划 | 区间型动态规划 | 背包型动态规划 )
算法动态规划 ④ ( 动态规划分类 | 坐标型动态规划 | 前缀划分型动态规划 | 前缀匹配型动态规划 | 区间型动态规划 | 背包型动态规划 )