【算法 | 实验7】以最小的步骤收集所有硬币(算法正确性还没想清楚)

简介: 题目最小步骤收集硬币有许多相邻排列的硬币堆。我们需要以最少的步骤收集所有这些硬币,在一个步骤中,我们可以收集一个水平线的硬币或垂直线的硬币,收集的硬币应该是连续的。输入描述输入第一行整数N表示硬币堆的数量

题目

最小步骤收集硬币

有许多相邻排列的硬币堆。我们需要以最少的步骤收集所有这些硬币,在一个步骤中,我们可以收集一个水平线的硬币或垂直线的硬币,收集的硬币应该是连续的。

输入描述

输入第一行整数N表示硬币堆的数量

输入第二行有N个整数分表表示硬币堆的高度

输出描述

采集所有硬币需要最小步骤

样例输入

5

2 1 2 5 1

样例输出

4

解析

第一行表示有五堆硬币,

第二行表示第一堆有两枚硬币,第二堆一枚硬币,依此类推。

取硬币需要4步,如图所示,取硬币的步骤用不同颜色的线段表示。

b7e1e5c1a2264ff29c94152637aaaa22.png

问题分析和算法设计思路

基本思路:分治法

从下方删除水平线总是有益的,于是以左图方式对硬币对进行分治,将一个原问题划分为 3 个子问题,递归求解。但我们还有纵向收集硬币的方法,每次都取两种方案的最小值。

左图:从下方删除水平线

右图:一直纵向取完所有硬币

468a0d9ba74e4ba380907ca0af9de2a7.png

有过的一些疑问

1、既然已经对问题分治了,干嘛还要和纵向取完所有硬币的情况进行比较?

分别用分治和纵向取硬币的思路考虑,只有一列硬币的情况:

048631e173cf4d5a953a57e64fb8c83b.png

2、既然直接一直分治不是最优,还要和纵向取完所有硬币的情况比较,那分治和纵向取完就能保证最优了吗?会不会有其它更好的策略?比如“先纵取硬币最多的一列”会不会更好?

比较严谨的证明我也没想出来。

不过我们也许不必太纠结先取行还是先取列的问题,从最初题目的图可以看到,它只是用线条将这些硬币划分成了 4 部分,而线条之间是没有顺序的。也就是说一些看似不同的决策其实是等价的

3、在问题社区提问:以最小的步骤收集所有硬币,如何证明该分治算法的正确性?

问题链接:https://ask.csdn.net/questions/7810917

有个博主回答如下,可以参考


首先你要审题,下方是重力方向,所以下方的硬币数量必然比上方的多,硬币不能悬空

而取硬币一共就两种取法,要么取一横排,要么取一竖列

如果先按竖列取,会把最下面的横排截断,所以显然不是最好的方法

而先按横排取,不会截断其它行列

那么你不从长的开始取,难道从最短的开始取吗

算法实现

参考代码:https://www.imangodoc.com/83929.html

#include <bits/stdc++.h>
using namespace std;
int minStepsRecur(int height[], int l, int r, int h)
{
    if (l >= r)
        return 0;
    int m = l;
    for (int i = l; i < r; i++)
        if (height[i] < height[m])
            m = i;
    return min(r - l,
               minStepsRecur(height, l, m, height[m]) + 
               minStepsRecur(height, m + 1, r, height[m]) + 
               height[m] - h);
}
int minSteps(int height[], int N)
{
    return minStepsRecur(height, 0, N, 0);
}
int main()
{
  int N = 0;
  cin >> N;
    int *height = new int[N];
    for(int i = 0; i < N; i++)
    {
      cin >> height[i];
  }
    cout << minSteps(height, N) << endl;
    return 0;
}

运行结果

aef376e6293041b0ac86f29bf6dadcbd.png

算法分析

时间复杂度:O ( N ) \Omicron (N)O(N),N 为硬币堆的数量

相关文章
|
3月前
|
算法
【算法】滑动窗口——长度最小的子数组
【算法】滑动窗口——长度最小的子数组
|
1月前
|
算法 搜索推荐 Java
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
这篇文章介绍了如何使用Java后端技术,结合Graphics2D和Echarts等工具,生成包含个性化信息和图表的海报,并提供了详细的代码实现和GitHub项目链接。
107 0
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
|
1月前
|
算法
计科一二班算法数据结构实验9答案
计科一二班算法数据结构实验9答案
14 0
|
3月前
|
算法 Java 测试技术
算法分析(蛮力法与减治算法应用实验报告)
这篇文章是关于算法分析的实验报告,介绍了如何使用蛮力法解决背包问题,并通过伪代码和Java代码实现,同时分析了其时间效率;还介绍了基于减治法思想实现的二叉查找树的插入与查找,同样提供了伪代码、Java源代码实现和时间效率分析,最后展示了测试结果截图。
算法分析(蛮力法与减治算法应用实验报告)
|
3月前
|
机器学习/深度学习 算法 Java
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
这篇文章介绍了基于贪婪技术思想的Prim算法和Dijkstra算法,包括它们的伪代码描述、Java源代码实现、时间效率分析,并展示了算法的测试用例结果,使读者对贪婪技术及其应用有了更深入的理解。
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
|
3月前
|
算法 Java 测试技术
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
这篇文章介绍了基于动态规划法的三种算法:解决背包问题的递归和自底向上实现、Warshall算法和Floyd算法,并提供了它们的伪代码、Java源代码实现以及时间效率分析。
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
|
3月前
|
算法 搜索推荐
算法设计 (分治法应用实验报告)基于分治法的合并排序、快速排序、最近对问题
这篇文章是关于分治法应用的实验报告,详细介绍了如何利用分治法实现合并排序和快速排序算法,并探讨了使用分治法解决二维平面上的最近对问题的方法,包括伪代码、源代码实现及时间效率分析,并附有运行结果和小结。
|
5月前
|
算法 程序员 数据处理
【数据结构与算法】使用单链表实现队列:原理、步骤与应用
【数据结构与算法】使用单链表实现队列:原理、步骤与应用
|
5月前
|
存储 算法 编译器
【数据结构与算法】使用数组实现栈:原理、步骤与应用
【数据结构与算法】使用数组实现栈:原理、步骤与应用
|
6月前
|
算法 C语言
[优选算法]------滑动窗⼝——209. 长度最小的子数组
[优选算法]------滑动窗⼝——209. 长度最小的子数组
下一篇
无影云桌面