• 动态规划:区间DP与环形DP


    区间型动态规划的典型例题是石子归并,同时使用记忆化搜索实现区间动归是一种比较容易实现的方式,避免了循环数组实现的时候一些边界的判断

    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=0x3f3f3f3f;
     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     for(int i=1;i<=n;i++)
    32     for(int j=1;j<=n;j++)
    33         f[i][j]=0x3f3f3f3f;
    34     cout<<dfs(1,n)<<endl;
    35     return 0;
    36 }

    这个问题还是比较显然的,我们考虑另一个问题,那就是环形动态规划

    其实环形动态规划也是区间型,只不过区间首尾相接

    此时使用记忆化搜索实现,其实是不容易的

    典型例题是能量项链

    先给出状态转移方程:

    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 }

    分别枚举区间的长度,区间的起点和区间中的任意点就好了

  • 相关阅读:
    700. Search in a Binary Search Tree
    100. Same Tree
    543. Diameter of Binary Tree
    257. Binary Tree Paths
    572. Subtree of Another Tree
    226. Invert Binary Tree
    104. Maximum Depth of Binary Tree
    1、解决sublime打开文档,出现中文乱码问题
    移植seetafaceengine-master、opencv到ARM板
    ubuntu16.04-交叉编译-SeetaFaceEngine-master
  • 原文地址:https://www.cnblogs.com/aininot260/p/9308791.html
Copyright © 2020-2023  润新知