服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C语言 深入探究动态规划之区间DP

C语言 深入探究动态规划之区间DP

2022-11-07 13:57小羊努力变强 C/C++

这几天在做有关dp的题,看到一个石子合并的问题,本来以为是个贪心,后来仔细一想压根不是贪心。贪心算法的思路是每次都取最大的,然而石子合并问题有个限制条件就是每次只能取相邻的,这就决定了它不是个贪心

写在前面

之前讲过背包问题,线性DP不知道大家忘了吗,这次是区间DP

石子合并

C语言 深入探究动态规划之区间DP

C语言 深入探究动态规划之区间DP

题意:

合并 N 堆石子,每次只能合并相邻的两堆石子,求最小代价

解题思路:

关键点:最后一次合并一定是左边连续的一部分和右边连续的一部分进行合并

状态表示:f[i][j]表示将 i 到 j 这一段石子合并成一堆的方案的集合,属性 Min

状态计算: (1) i<j 时,f[i][j]=min f[i][k]+f[k+1][j]+s[j]−s[i−1] (2)i=j 时,

f[i][i]=0(合并一堆石子代价为 0)

问题答案: f[1][n]

所有的区间dp问题枚举时,第一维通常是枚举区间长度,并且一般 len = 1 时用来初始化,枚举从 len = 2 开始;第二维枚举起点 i (右端点 j 自动获得,j = i + len - 1)

模板代码如下:

for (int len = 1; len <= n; len++) {         // 区间长度
  for (int i = 1; i + len - 1 <= n; i++) { // 枚举起点
      int j = i + len - 1;                 // 区间终点
      if (len == 1) {
          dp[i][j] = 初始值
          continue;
      }

      for (int k = i; k < j; k++) {        // 枚举分割点,构造状态转移方程
          dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + w[i][j]);
      }
  }
}

最后总的代码:

#include <iostream>
#include <cstring>

using namespace std;

const int N = 307;

int a[N], s[N];
int f[N][N];

int main() {
  int n;
  cin >> n;

  for (int i = 1; i <= n; i ++) {
      cin >> a[i];
      s[i] += s[i - 1] + a[i];
  }

  memset(f, 0x3f, sizeof f);
  // 区间 DP 枚举套路:长度+左端点 
  for (int len = 1; len <= n; len ++) { // len表示[i, j]的元素个数
      for (int i = 1; i + len - 1 <= n; i ++) {
          int j = i + len - 1; // 自动得到右端点
          if (len == 1) {
              f[i][j] = 0;  // 边界初始化
              continue;
          }

          for (int k = i; k <= j - 1; k ++) { // 必须满足k + 1 <= j
              f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
          }
      }
  }

  cout << f[1][n] << endl;


  return 0;
}

到此这篇关于C语言 深入探究动态规划之区间DP的文章就介绍到这了,更多相关C语言 区间DP内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_54847231/article/details/123910489

延伸 · 阅读

精彩推荐
  • C/C++C/C++中抽象类详解及其作用介绍

    C/C++中抽象类详解及其作用介绍

    这篇文章主要介绍了C/C++中抽象类详解及其作用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    我是小白呀7612021-12-28
  • C/C++C++实现简单插件机制原理解析

    C++实现简单插件机制原理解析

    这篇文章主要介绍了C++实现简单插件机制原理解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    kiven.li8562021-10-22
  • C/C++C++实现水仙花数判断实例

    C++实现水仙花数判断实例

    大家好,本篇文章主要讲的是C++实现水仙花数判断实例,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览...

    Alkaid#352911932022-08-09
  • C/C++OpenGL绘制三次Bezier曲线

    OpenGL绘制三次Bezier曲线

    这篇文章主要为大家详细介绍了OpenGL绘制三次Bezier曲线,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    wyg19975482021-09-01
  • C/C++C++实现考勤管理系统

    C++实现考勤管理系统

    这篇文章主要介绍了C++实现考勤管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    我不叫喂喂喂喂喂喂喂喂6382022-10-20
  • C/C++VS2010+Opencv+MFC读取图像和视频显示在Picture控件

    VS2010+Opencv+MFC读取图像和视频显示在Picture控件

    这篇文章主要为大家详细介绍了VS2010+Opencv+MFC读取图像和视频显示在Picture控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Hello_________Word11072021-08-01
  • C/C++利用C++ OpenCV 实现从投影图像恢复仿射特性

    利用C++ OpenCV 实现从投影图像恢复仿射特性

    我们通过相机拍摄的图片存在各种畸变,其中投影畸变使得原本平行的直线不再平行,就会产生照片中近大远小的效果。本文将具体介绍如何利用OPenCV实现...

    tan_tao3756822022-03-07
  • C/C++C++程序内存栈区与堆区模型案例分析

    C++程序内存栈区与堆区模型案例分析

    一直以来总是对这个问题的认识比较朦胧,我相信很多朋友也是这样的,总是听到内存一会在栈上分配,一会又在堆上分配,那么它们之间到底是怎么的区...

    Zachery.8542022-11-01