贪心算法

贪心策略

回眸只為那壹抹淺笑 提交于 2019-12-19 12:38:58
之所以称之为“策略”,而不是“算法”,还是有些原因的,贪心思想和动态规划思想练习紧密,可是细想一下有不能混为一谈,动态规划是根据迁移过程的状态去推导下一过程的状态,是有理论依据的,通过每次“完美”的检验而得出最优解,关键是找出一个最优子结构,记得经典的一句话是:动态规划的子结构必须是独立的,而且是重叠的,虽然是一组反义词,可是代表的意义是不同的。扯远了,而贪心策略不同,贪心只考虑当前的最优解,是临时的,不连续的,所以得出的解不一定是最优解。 一个最间的的例子就是0-1背包问题,根据贪心,每次都放进去最“实惠”的,也就是“性价比”最高的,然后放次高的,直到不能放,这样做显然是不尽人意的,因为贪心策略没有考虑到背包的容量,为什么?前面说过了,贪心策略只考虑当前的最优解,他是不会管背包容量的,如果加入了背包容量这个参数,便成为DP问题了,贪心策略缺少一约束条件,贪心找出的每一条路径都是最大可能接近最优解的,例如:每条路径是最优解的可能性是0.8,贪心一共做了4次检查,于是正确的最优解得可能是(0.8)^4,可是他没有考虑其他的情况,问题就出现了。当然,贪心也有很多正确的策略,只是不适用某一问题罢了。 *********************************************************************** 下面开始看看贪心算法: 一.贪心算法的基本概念

可用贪心算法解决的几个基本问题

我的梦境 提交于 2019-12-19 12:38:40
可用贪心算法解决的几个基本问题 分类: 算法 2011-08-24 12:36 950人阅读 评论 (0) 收藏 举报 算法 活动 作业 c 关键:看问题有没有贪心选择性质和最优子结构性质。有些问题看似是可以用贪心算法,但是实际用贪心算法却得不到最优解。构造贪心算法后,需要一定的证明来确定它的正确性。常用证明方法:反证法、调整法。 几个基本问题: 1. 活动安排问题。 设有n个活动的集合e={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间si和一个结束时间f i ,且s i <f i 。如果选择了活动i,则它在区间[s i ,f i ]内占用资源。若区间[s i ,f i ]与区间[s j ,f j ]不相交,则称活动i与活动j是相容的。也就是说,当s j ≥fi或s i ≥f j 时,活动i与活动j相容。活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合。 解决方法:先选择结束时间最早的那一个活动,然后往后依次查找结束时间最近的不冲突的活动加入。 2. 可以解决背包问题,不能解决0-1背包问题。 0-1背包问题: 给定n种物品和一个背包。物品i的重量是Wi,其价值为Vi,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时

贪心算法之最少区域覆盖

时光毁灭记忆、已成空白 提交于 2019-12-18 20:26:30
Description 给出n个区间的起点和终点,求最少使用其中多少个区间可以将所有区间所在的区域完全覆盖。(测试的数据确保这1点)。 Input 第1行一个整数n,表示n个区间; 第2行开始n行,每行2个整数,表示一个区间范围。 Output 按区间先后顺序,输出选中的区间。 Sample Input 7 1 5 1 6 3 6 1 7 6 9 9 10 7 9 Sample Output 1 7 6 9 9 10 算法思想 将区间按照左端点从小到大排序,左端点相同按右端点从小到大排序 每次都找到左端点在已覆盖区域内,右端点尽可能长的区间 # include <iostream> # include <algorithm> using namespace std ; class Section { public : int num1 ; int num2 ; } ; // 根据区间的左端点进行升序排序 // 左端点一致的根据右端点升序排序 bool cmp ( Section s1 , Section s2 ) { if ( s1 . num1 < s2 . num1 ) return true ; else if ( s1 . num1 == s2 . num1 && s1 . num2 < s2 . num2 ) return true ; else return false

贪心 - K重Huffman编码

时光毁灭记忆、已成空白 提交于 2019-12-18 15:17:06
* 问题描述: 设要传输由 n 种基本字符构成的一段信息。已知每种字符在信息中出现的频次 w[i], 1 ≤ i ≤ n (即第 i 种字符在一段信息中出现 w[i] 次)。现在要对这 n 种字符构造一种不等长无歧义的 k 进制前缀编码,使得传输该段信息的编码总长度最短。求该最短长度。 * 基本思路: 一般算法课都会介绍Huffman编码,它就是该问题在 k = 2 下的一种特例。自然的,会想到用类似Huffman算法来解决该问题。 一种典型的错误: 相信有些同志一开始会直接“无脑”地将Huffman算法中的 2 改成 k,即:首先把 n 个结点依次放入一个小顶堆(频次 w 最小的结点位于堆顶);然后不断地依次从堆顶取出 k 个结点“捏”在一起构成一个新结点,新结点权重为 k 个子结点之和,并将其放回堆中。当堆中的结点数 ≤ k 时,合并成Huffman树的根节点,算法结束。 这种算法有一个致命的问题,即这样做生成的树根结点的孩子可能不满 k 个,这显然不是最短的编码方案。因为把任一非根结点孩子的叶节点改为根结点的孩子后得到的编码长度一定更短。如下图所示。 注意到:(1) 对于满足条件的 k 叉Huffman树,每个结点为根的子树都构成一棵满足条件的 k 叉Huffman树。 (2) 任一子树的根结点的父结点必有 k-1 个兄弟。第(2)点可用反证法证明

贪心算法1002

夙愿已清 提交于 2019-12-18 01:06:59
题目大意: 田忌赛马。。。。若干匹马与国王的马比赛,每有一匹马大于国王的速度,赢得200,否则输200,速度相同不计,输入n为马的数目,0为结束 解题思路: 先排序,将两个速度最快的比较,如果大于国王,m++,如果小于,将最慢的与国王最快的比较,m--。如果等于,将两个最慢的比较,如果大于国王最慢的,m++,如果小于,与国王最快的比较m--,如果等于,将最慢的与国王最快的比较,m--; 代码: #include <iostream> #include <algorithm> using namespace std; int main() { int n,i,m=0,a[1001],b[1001]; while(cin>>n) { if(n==0) return 0; for(i=0;i<n;i++) cin>>a[i]; for(i=0;i<n;i++) cin>>b[i]; sort(a,a+n); sort(b,b+n); int l1=0,l2=0;int h1=n-1,h2=n-1; for(i=0;i<n;i++) { if(a[h1]>b[h2]) { m++; h1--; h2--; continue; } if(a[h1]<b[h2]) { m--; h2--; l1++; continue; } if(a[h1]==b[h2]) { if(a[l1]<b[l2])

解题报告 一维数组 贪心算法

假装没事ソ 提交于 2019-12-15 20:59:04
题目 核心代码 流程图 遇到的困难及解决办法 最开始考虑这道题的时候是想将s数组里的数慢慢相加 每当和>=100时 便清零并且重新设置一个容量为100的箱子 继续存储 结果编译起来十分困难。 后来逆向思维 先构造一定数量的容量均为100的一维数组box[] 然后存放 用容量减去s数组里的元素 每当容量即将<=0时 便开始使用下一个box中的元素进行计算。 面对思路较为清晰 但编译较为麻烦时 可以逆转思维 减少编译时遇到的困难。 来源: https://www.cnblogs.com/lowkey1019/p/12045827.html

贪心算法

╄→гoц情女王★ 提交于 2019-12-11 00:18:27
贪心算法 1.求最优解 2.将一个大问题拆分成若干局部问题,局部问题的每一步产生的最优解无后效性(即之后的状态求出的最优解跟之前的状态无关) 分享一个leetcode的题目: 盛最多水的容器 给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 说明:你不能倾斜容器,且 n 的值至少为 2。 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 示例: 输入: [1,8,6,2,5,4,8,3,7] 输出: 49 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/container-with-most-water 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 我的题解 贪心,最大面积取决于左右两根柱子最小的高度,和两根柱子的距离 思路: 把一根柱子替换成另一根柱子要保证被替换的是小的那根 area = [left-right]*min(leftHeight,rightHeight); area1 = [(left+1)-right]*min

贪心算法经典例子

时光总嘲笑我的痴心妄想 提交于 2019-12-08 05:58:39
一、定义 什么是贪心算法呢?所谓贪心算法是指,在对问题求解时,总是做出在当前看来最好的选择。也就是说,不从整体最优解出发来考虑,它所做出的仅是在某种意义上的局部最优解。 贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题都能产生整体最优解或整体最优解的近似解。 贪心算法的基本思路如下: 1.建立数学模型来描述问题。 2.把求解的问题分成若干个子问题。 3.对每个子问题求解,得到每个子问题的局部最优解。 4.把每个子问题的局部最优解合成为原来问题的一个解。 实现该算法的过程: 从问题的某一初始状态出发; while 能朝给定总目标前进一步 do 求出可行解的一个解元素; 由所有解元素组合成问题的一个可行解; 二、例题分析 [ 活动安排问题 ] 活动安排问题是可以用贪心算法有效求解的一个很好的例子。该问题要求高效地安排一系列争用某一公共资源的活动。贪心算法提供了一个简单、漂亮的方法使得尽可能多的活动能兼容地使用公共资源。 设有n个活动的集合e={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si< fi。如果选择了活动i,则它在半开时间区间[si,fi]内占用资源。若区间[si,fi]与区间[sj,fj]不相交,则称活动i与活动j是相容的

C语言合并果子-贪心算法

时光总嘲笑我的痴心妄想 提交于 2019-12-07 23:55:29
/*有几堆水果。每次你把两堆东西移到一起,形成更大的一堆。每个动作消耗的能量是两堆水果的总重量。如何把所有的水果堆在一起,消耗最少的能量?*/ 以上是题目,该题首先要读懂题目,每次移到一起以后都要将数组重新排序再次移动。 1 #include<stdio.h> 2 3 int main(){ 4 5 int t, n, m = 0; 6 int i = 0, j = 0; 7 scanf("%d",&n); 8 int sum[n]; 9 10 for(i = 0; i<n;i++){ 11 scanf("%d",&sum[i]); 12 } 13 14 for(i = 0; i<n-1;i++){ 15 for(j = 0; j<n-i-1; j++){ 16 if(sum[j]>sum[j+1]){ 17 t = sum[j]; 18 sum[j] = sum[j+1]; 19 sum[j+1] = t; 20 } 21 } 22 } 23 for(i = 1;i<n;++i){ 24 sum[i] += sum[i-1]; 25 m += sum[i]; 26 for(j = i+1;j<n&&sum[j]<sum[j-1];++j){ 27 t = sum[j-1]; 28 sum[j-1] = sum[j]; 29 sum[j] = t; 30 } 31 } 32 33

贪心算法初探3——最短路径(Dijkstra算法)

筅森魡賤 提交于 2019-12-07 15:44:26
  问题描述:给定有向带权图G=(V,E),其中每条边的权是非负实数。此外,给定V中的一个顶点,称为源点。现在要计算从源点到所有其他各顶点的最短路径长度,这里路径长度指路上各边的权之和。   算法设计:这个问题一般采用迪杰斯特拉算法(Dijkstra)算法思想是先求出长度最短的一条路径,再参照该最短路径求出长度次短的一条路径,直到求出从源点到其他各个顶点的最短路径。   算法基本思想:先假定源点为u,顶点集合V被划分为两部分:集合V以及集合V-S。初始时S中仅含有u,其中S的顶点到源点的最短路径已经确定。集合V-S中华包含的顶点到源点的最短路径长度待定,称从源点出发只经过S中的点到V-S中点的路径为特殊路径,并用数组dict[]记录当前每个顶点所对应的最短特殊路径长度。   贪心策略选择:选择特殊路径长度最短的路径,将其连接的V-S顶点加入到集合S中,同时更新数组dict[].一旦S包含了所有的顶点,dict[]就储存了从源到所有其他顶点之间的最短路径长度。   算法详情:   1:设置地图带权邻接矩阵为map[][],如果从源点u到顶点i有边,就map[u][i]等于<u,i>的权值,否则map[u][i]=∞;使用一维数组dict[i]记录从源点到i顶点的最短路径长度;使用一维数组p[i]记录最短路径上i顶点的前驱。   2:设置一个集合S={u},对于集合V-S中所有顶点x