一:前言:

关于石子合并,这个问题分为链型和环形两种,本题当中用的是环形,但我们在学习动态规划,所以多练肯定是有好处的,况且将链型的问题解决后,更容易理解环形的解决方法,所以本次题解分为两部分链型和环型两部分

二:石子合并(链型)

1.题目

题目】
设有N堆石子排成一排,其编号为1,2,3,
每堆石子有一定的质量,可以用一个整数来描述,现在要将这N堆石子
合并成为一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的质
量之和,合并时由于选择的顺序不同,含并的总代价也不相同。
问题是:找出一种合理的方法,使总的代价最小,输出最小代价。
输入格式】
第一行一个数,N表示石子的堆数。1≤N≤300
第二行N个数,表示每堆石子的质量(均不超过1000
输出格式】
输出一个整数,表示最小代价。
【输入样例】

5
1 3 4 2 5

【输出样例

34

2:思路:

思路:
1.判断动态规划
这里最终的结果,其求解过程 也是跳跃性的,所以还是动态规划
2.分析题意
并且这里涉及到网格(就是建立二维数组),根据合并不同的堆
其合并的和是不一样的,故这里有涉及到划分,所以我们又可以
联想到相似的解法(矩阵链相乘)
3.求其递推方程
其递推方程:m[i][j] = m[i][k]+m[k+1][j] + sum [j] - sum [i -1];
4.递推方程的解释:
前面的m[i][k] 和 m[k+1][j] :i到k合并成一堆,k+1到j又合并成一堆
后面的sum[j] - sum[i -1]: 这里表示的是刚形成的两堆 再合并到一块的石子数
也就是用前缀和来求区间和
比如有(1,2,3,4,5,6)这里表示的是有6堆石子
现在我们求m[3][6] = m[3][4]+m[5][6] + sum[6] - sum[2]

                           sum[6]:表示的是将这6堆全部合并在一起 sum[2]:表示的是将前两堆合并在一起现在我们要求后4堆的和 那不就是sum[6] - sum [2];

3.上码


/**思路:1.判断动态规划  这里最终的结果,其求解过程 也是跳跃性的,所以还是动态规划2.分析题意 并且这里涉及到网格(就是建立二维数组),根据合并不同的堆其合并的和是不一样的,故这里有涉及到划分,所以我们又可以联想到相似的解法(矩阵链相乘)3.求其递推方程   其递推方程:m[i][j] = m[i][k]+m[k+1][j] + sum [j] - sum [i -1];4.递推方程的解释:前面的m[i][k] 和 m[k+1][j] :i到k合并成一堆,k+1到j又合并成一堆后面的sum[j] - sum[i -1]: 这里表示的是刚形成的两堆 再合并到一块的石子数也就是用前缀和来求区间和 比如有(1,2,3,4,5,6)这里表示的是有6堆石子现在我们求m[3][6] = m[3][4]+m[5][6] + sum[6] - sum[2] sum[6]:表示的是将这6堆全部合并在一起 sum[2]:表示的是将前两堆合并在一起现在我们要求后4堆的和 那不就是sum[6] - sum [2];        */// 我们要求的是最小次数 #include<bits/stdc++.h>
using namespace std;
#define infinite 99 int main(){int N;int m[100][100];//注意二维数组不能开的太大 cin >> N;int sum[N+1];//求前缀和int a[N+1];//记录每堆的石子数量 //因为我们要求的是最小次数 故我们将数组先进行赋最大值for(int i = 0; i < 100; i++){for(int j = 0; j < 100; j++){m[i][j] = infinite; }} for(int i = 1; i <= N; i++){cin >> a[i];sum[i] = sum[i-1] + a[i];//记录前缀和 m[i][i] = 0;//自己 到自己肯定不能合并啊   }//  for(int i = 0; i <= N; i++){//      cout << sum[i] << ' ';
//  }
//  //开始更新网格for(int i = N; i >= 1; i--){for(int j = i + 1; j <= N; j++){//这里的i+1是指的是在i后面进行划分 m[i][j] = m[i][i] + m[i+1][j] + sum[j] - sum[i - 1];for(int k = i+1; k < j; k++){//这里的i+1指的是在i后面进行划分  k < j 指的是k在j之前划分 int temp = m[i][k] + m[k+1][j] + sum[j] - sum[i-1];if(temp < m[i][j]){m[i][j] = temp;}}        }} //   for(int i = 1; i <= N; i++){//      for(int j = 1; j <= N; j++){//          cout << m[i][j] << ' ' << ' ' << ' ' << ' ';
//      }
//      cout << endl;
//  }cout << m[1][N]; }//测试用例一:
//5
//1 3 4 2 5//34//测试用例二:
//4
//4 5 9 4
//0    9    27    44
//0    0    14    31
//0    0    0    13
//0    0    0    0//44 

三:石子合并(环形 (本题题解7-10))

1.题目:

在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 N 堆石子合并成 1 堆的最小得分和最大得分。

输入格式:
数据的第 1 行是正整数 N ,表示有 N 堆石子。

第 2 行有 N 个整数,第 i 个整数 a
i

表示第 i 堆石子的个数。

输出格式:
输出共 2 行,第 1 行为最小得分,第 2 行为最大得分。

输入样例:

4
4 5 9 4

输出样例:

43
54

2.思路:

思路:这里是环形的,我们把环形的每次连接的地方依次剪开,变成链型的
那么就有一种思路 就是将输入的数组复制两次,那么的话,我们每次一次
取出N个元素,就实现了,不同的链接处的分割,然后求出最后结果时候
根据划分的不同我们按最大或或最小值选取最后的结果

3.上码:


/**思路:这里是环形的,我们把环形的每次连接的地方依次剪开,变成链型的那么就有一种思路 就是将输入的数组复制两次,那么的话,我们每次一次取出N个元素,就实现了,不同的链接处的分割*/ #include<bits/stdc++.h>
using namespace std;int main(){int N;int max_tone[300][300];int min_tone[300][300];cin >> N;int a[2*N+1];int sum[2*N+1];sum[0] = 0;//需要给sum[0] 赋初值,否则sum[0] 是个很大的数 //  //注意下方的代码:数组的列均变为原来的2倍 行是不变的
//  for(int i = 0; i <= N; i++){//      for(int j = 0; j <= 2*N; j++){//          max_tone[i][j] = 0;
//          min_tone[i][j] = 9999;
//      }
//  }for(int i = 1; i <= N; i++){cin >> a[i];a[i+N] = a[i];}for(int i = 1; i <= 2*N; i++){sum[i] = sum[i-1] + a[i];max_tone[i][i] = 0;min_tone[i][i] = 0;}//  for(int i = 0; i <= 2*N; i++){//      cout << sum[i] << ' ';
//  }
//  //开始更新网格for(int i = 2*N; i >= 1; i--){for(int j = i+1; j < i+N && j <= 2*N; j++){//这里的j < i+N,是确定每次划分的范围为N个 max_tone[i][j] = max_tone[i][i] + max_tone[i+1][j] + sum[j] - sum[i-1];min_tone[i][j] = min_tone[i][i] + min_tone[i+1][j] + sum[j] - sum[i-1];for(int k = i + 1; k < j; k++){int temp1 = max_tone[i][k] + max_tone[k+1][j] + sum[j] - sum[i-1];int temp2 = min_tone[i][k] + min_tone[k+1][j] + sum[j] - sum[i-1];//求取最大值 if(temp1 > max_tone[i][j]){max_tone[i][j] = temp1;} //求取最小值if(temp2 < min_tone[i][j]){min_tone[i][j] = temp2;}     }       } } //
//      for(int i = 1; i <= N; i++){//      for(int j = 1; j <= 2*N; j++){//          cout << min_tone[i][j] << ' ';
//      }
//      cout << endl;
//  }//因为 我们从合并的两个数组中每次选取出N个元素,即1到N,2到N+1,N到i+N-1为止,再往下就出现重复了int maxx = 0,minn = 9999;for(int i = 1; i <= N; i++){maxx = max(max_tone[i][i+N-1],maxx);minn = min(min_tone[i][i+N-1],minn); } cout  << minn << endl << maxx; } //4
//4 5 9 4//0 9 27 44 0 0 0 0
//0 0 14 31 44 0 0 0
//0 0 0 13 25 43 0 0
//0 0 0 0 8 21 43 0//0 9 27 36 0 0 0 0
//0 0 14 23 35 0 0 0
//0 0 0 9 17 31 0 0
//0 0 0 0 4 13 31 0

这个图是给我自己看的 太乱了啊 方便我理解当时候我的思路 怕草稿本子丢了,找不到当初的想法了

四:总结

如果看到我前面的题解,你会发现,代码思路几乎一致,都是划分网格,推出递推方程,本题的题解其实和前面的矩阵连相乘思路相似,所以兄弟们,请认真做每一道题,思路都是融会贯通的,算法题本来就很难理解,所以需要很长时间去打磨,注意题解当中的每次的取值范围,均需想明白!!

五:数据结构和算法分析思维导图

如果想看一下的我们知识体系, 我分享一张我收藏的思维导图(仅供参考)

加油boy!成功本就不易,我们共勉 有疑问可以留言!!!

7-10 石子合并 (10 分)相关推荐

  1. R7-11 h0096. 单词合并 (10 分)

    R7-11 h0096. 单词合并 (10 分) 在美国的很多报纸上,有一种单词游戏 Jumble .这一游戏的目的是解字谜,为了找到答案中的字母,就要整理 4 个单词.请您编写一个整理单词的程序. ...

  2. PTA20、字典合并 (10 分)

    20.字典合并 (10 分) 字典合并.输入用字符串表示两个字典,输出合并后的字典,字典的键用一个字母或数字表示.注意:1和'1'是不同的关键字! 输入格式: 在第一行中输入第一个字典字符串 在第二行 ...

  3. 面试题 10.01. 合并排序的数组

    面试题 10.01. 合并排序的数组 思路:①把B数组放在A数组后面,然后排序.O((n+m)²),太蠢了代码不写 ②copyA数组,然后两个指针判度copyA,和B的值那个小,小的放在A数组中,然后 ...

  4. HTML5 权威指南第 10 章 文档分节 学习笔记

    HTML5 权威指南第 10 章 文档分节 学习笔记 第 8 章 标记文字 内容从从文字出发,专注如何将单体内容正确的呈现出来:第 9 章 组织内容 内容从段落出发,专注如何将单体内容合理的放在段落中 ...

  5. Leetcode面试题 10.01. 合并排序的数组(C语言)

    Leetcode面试题 10.01. 合并排序的数组(C语言) 题目: 给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B. 编写一个方法,将 B 合并入 A 并排序.初始化 ...

  6. 7-10 jmu-c-二进制转10进制 (20分)

    7-10 jmu-c-二进制转10进制 (20分) 输入一组二进制字符,输出其对应的十进制数.当输入回车键时,输入结束.若输入非二进制字符,输出error input! 输入样例1: 11111111 ...

  7. 解决Windows 10笔记本接显示器分屏后没有声音的问题

    解决Windows 10笔记本接显示器分屏后没有声音的问题 参考文章: (1)解决Windows 10笔记本接显示器分屏后没有声音的问题 (2)https://www.cnblogs.com/lzhu ...

  8. 10 判断素数 (10分)

    字节跳动校招内推码: C4BDSMC 投递链接: https://job.toutiao.com/s/J691fRK 内推交流QQ群:1049175720 think: 1素数:除1以外只能被其自身整 ...

  9. usb扩展坞同时接键盘鼠标_雷柏XD200 USB-C 10口扩展坞分线转换器上市

    近年来笔记本市场掀起一阵轻薄风,轻巧的机身让移动办公一族充分享受到了轻薄本带来的便利.而iPad Pro等高性能平板电脑,也受到不少轻办公.轻娱乐用户的青睐.不过为了追求轻巧,不少轻薄本取消了USB. ...

最新文章

  1. php http面向对象编程实例,PHP面向对象编程——PHP对象引用实例代码
  2. 毕业仅1年,干Python赚了50W 网友:不是吹的
  3. 清理Mac上的软件容易吗?
  4. Java实用面试题及参考答案分享
  5. 生产计划到底该怎样改进?这6点帮你节省至少60%的计划时间
  6. 回忆一 --- 去年6月面试进入公司的日子
  7. .NET 分布式自增Id组件(解决自动分配机器Id、时间回拨问题)
  8. Android studio提示Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.
  9. 商户分账交易汇总和商户交易汇总不一致
  10. 调试安装php源码,Xdebug的安装与配置,帮助调试PHP程序
  11. 0xc0000001报错解决办法
  12. CGI入门一:使用C++实现CGI程序
  13. latex中脚注内容不显示
  14. Ubuntu下启动图形界面startx报错connection to X server lost
  15. 关于sqlserver身份登录失败的解决方法
  16. CSS五种方式实现 Footer 置底
  17. 一文带你快速了解常用的CSS选择器场景
  18. 互联网战神谷歌大牛Jeff Dean
  19. 【计算机网络】思科实验(8):网络地址转换之路由器动态NAT模拟
  20. 第5课:scratch3的作品如何转换成HTML5文件

热门文章

  1. 第二章指南(4.2)添加 Controller
  2. 使用webpack搭建个性化项目
  3. 英语自动提取高频词_斑马英语提分营免费体验课
  4. CSDN博客文章阅读模式插件(附源码)
  5. 【ArcGIS风暴】ArcGIS解决数字化之前创建图层时未定义坐标系而导致数据跑偏的问题
  6. C语言试题三之计算并输出 s=1+(1+2^(0.5))+(1+2^(0.5)+3^(0.5))+…+(1+2^(0.5)+3^(0.5)+…+n^(0.5))
  7. Android之TabLayout+ViewPager2+FragmentStateAdapter实现带数字变化的TAB选项
  8. C和指针之函数之可变参数
  9. 用非递归方式实现二叉树后序遍历
  10. 七、功能性组件与事件逻辑(IVX 快速开发教程)