区间型动态规划的记忆化搜索实现与环形动态规划的循环数组实现
Posted aininot260
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区间型动态规划的记忆化搜索实现与环形动态规划的循环数组实现相关的知识,希望对你有一定的参考价值。
区间型动态规划的典型例题是石子归并,同时使用记忆化搜索实现区间动归是一种比较容易实现的方式,避免了循环数组实现的时候一些边界的判断
n堆石子排列成一条线,我们可以将相邻的两堆石子进行合并,合并之后需要消耗的代价为这两堆石子的质量之和,问最小的合并代价
状态转移方程很容易给出:
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[i][j])
因为要计算区间和,考虑前缀和进行预处理
然后我们给出用记忆化搜索形式实现的代码,这里的记忆化搜索形式可以作为后续问题的一个模板
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int INF=0x7fffffff; 6 const int maxn=105; 7 int n; 8 int w[maxn]; 9 int g[maxn]; //前缀和 10 int f[maxn][maxn]; 11 int dfs(int l,int r) 12 { 13 if(l==r) return 0; 14 if(f[l][r]!=INF) 15 return f[l][r]; 16 int tmp=INF; 17 for(int i=l;i<r;i++) 18 tmp=min(tmp,dfs(l,i)+dfs(i+1,r)+g[r]-g[l-1]); 19 if(tmp<f[l][r]) 20 f[l][r]=tmp; 21 return f[l][r]; 22 } 23 int main() 24 { 25 cin>>n; 26 for(int i=1;i<=n;i++) 27 { 28 cin>>w[i]; 29 g[i]=g[i-1]+w[i]; 30 } 31 memset(f,127,sizeof(f)); 32 cout<<dfs(1,n)<<endl; 33 return 0; 34 }
这个问题还是比较显然的,我们考虑另一个问题,那就是环形动态规划
其实环形动态规划也是区间型,只不过区间首尾相接
此时使用记忆化搜索实现,其实是不容易的
典型例题是能量项链
先给出状态转移方程:
f[i][j]=max(f[i][j],f[i][k]+f[k][j]+a[i]*a[j]*a[k])
由于每一种区间问题的价值计算方式不一样,可能采用不同的优化形式,本题直接计算即可
然后我们给出使用循环数组方式实现的一个固定的格式,所有的区间型动态规划都可以采取这样的形式来实现
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 const int maxn=1005; 5 int n; 6 int a[maxn]; 7 long long ans=0; 8 int f[maxn][maxn]; 9 void dp() 10 { 11 for(int l=2;l<=n;l++) //区间长度 12 for(int i=1;i<=n*2-l+1;i++) //区间起点 13 { 14 int j=i+l; //区间终点 15 for(int k=i+1;k<=j-1;k++) //区间中任意点 16 f[i][j]=max(f[i][j],f[i][k]+f[k][j]+a[i]*a[j]*a[k]); 17 } 18 for(int i=1;i<=n;i++) 19 if(ans<f[i][i+n]) 20 ans=f[i][i+n]; 21 } 22 int main() 23 { 24 cin>>n; 25 for(int i=1;i<=n;i++) 26 { 27 cin>>a[i]; 28 a[n+i]=a[i]; 29 } 30 dp(); 31 cout<<ans; 32 return 0; 33 }
分别枚举区间的长度,区间的起点和区间中的任意点就好了
以上是关于区间型动态规划的记忆化搜索实现与环形动态规划的循环数组实现的主要内容,如果未能解决你的问题,请参考以下文章
动态规划区间计数数位统计状态压缩树形DP与记忆化搜索 题解与模板