算法-贪心算法

贪心算法大学的时候就已经学过也弄过,可能周末确实没想到写什么,就顺手学了当年学习的知识,贪心算法(也称为贪婪算法),贪心算法总是作出在当前看来最好的选择。贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。当然,希望贪心算法得到的最终结果也是整体最优的。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。

贪心要素

概念就是这样,如果需要详情可继续搜索获取更多信息,这个时候出现了一个问题,什么使用贪心算法?只需要满足两点即可,首先就是所求解的问题最优解可以一系列局部最优来达到解决,其次一个问题的最优解中是否包含一个子问题的最优解,也称为最优子结构,一般如果包含子问题的最优解可以通过动态算法或者贪心算法来求解。简单说就是贪心策略适用的前提是:局部最优策略能导致产生全局最优解。一般的解题框架:

从问题的某一初始解出发;

while (能朝给定总目标前进一步)

{

利用可行的决策,求出可行解的一个解元素;

}

由所有解元素组合成问题的一个可行解;详情可参考Demo.

贪心Demo

贪心Demo这哥们大一就出现在一个很经典的C语言题目中,背包问题,有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。(跟0-1背包不同,0-1需要使用到动态规划)

物品 A  B  C  D  E  F  G

重量 35 30 60 50 40 10 25

价值 10 40 30 50 35 40 30

解题思路:

约束条件是装入的物品总重量不超过背包容量:∑wi<=M( M=150)。

(1)根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优?

(2)每次挑选所占重量最小的物品装入是否能得到最优解?

(3)每次选取单位重量价值最大的物品,成为解本题的策略。

就是这个猜想一下然后需要证明的,能看博客的基本上也明白第三种是最优的答案,一般这种题晚上有C代码,C++代码,C#代码比较少,我没事写了写,将就看下,定义一个物品的类:

   public class Product
        {
            public string Name { get; set; }
            public float Weight { get; set; }
            public float Value { get; set; }
            public float UnitValue { get; set; }
        }

 控制台代码,代码比较简单:

  float[] weight = new float[] { 35, 30, 60, 50, 40, 15, 20 };
            float[] value = new float[] { 10, 40, 30, 50, 35, 40, 30 };
            string[] name = new string[] { "A", "B", "C", "D", "E", "F", "G" };
            List<Product> list = new List<Product>();
            for (int i = 0; i < weight.Length; i++)
            {
                Product product = new Product();
                product.Name = name[i];
                product.Weight = weight[i];
                product.Value = value[i];
                product.UnitValue = value[i] / weight[i];
                list.Add(product);
            }
            float sum = 0;
            foreach (Product item in list)
            {
                Console.Write(item.Name + "-" + item.UnitValue+"\t");
            }
            List<Product> result = new List<Product>();
            foreach (var product in list.OrderByDescending(item => item.UnitValue))
            {
                sum += product.Weight;
                if (sum > 150) break;
                result.Add(product);
            }
            foreach (var product in result)
            {
                Console.Write(product.Name + "--" + product.Weight+"\t");
            }
            Console.WriteLine();
            Console.WriteLine("总价值:" + result.Sum(item => item.Value) + "\t总重量:" + result.Sum(item => item.Weight));
            Console.ReadKey();

 结果如下:

这样求出的最优结果是物品没有分割的情况的,有的是要求切割的,结果如何就看怎么算了;

背包算是过去的,还有一个是绕不过的会议,老师讲课的还经常拿上课的教师做例子,先看下题目:

设有N个活动时间集合,每个活动都要使用同一个资源,比如说会议场,而且同一时间内只能有一个活动使用,每个活动都有一个使用活动的开始si和结束时间fi,即他的使用区间为(si,fi),现在要求你分配活动占用时间表,即哪些活动占用该会议室,哪些不占用,使得他们不冲突,要求是尽可能多的使参加的活动最大化,即所占时间区间最大化~

看着费劲的话那就看张网络图片吧,i表示活动,S[i]开始时间,f[i]表示结束时间:

这个题目也很简单,需要想清楚的一点的就是如果两个活动需要相容,那么第二个活动的开始时间一定要大于等于第一个活动的结束时间,想清楚了这个就OK了;

    int[] start = { 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12 };
            int[] end = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
            List<int> list = new List<int>() { 0 };
            int j = 0;
            for (int i = 1; i < start.Length; i++)
            {
                if (start[i] >= end[j])
                {
                    list.Add(i);
                    j = i;
                }
            }
            for (int i = 0; i < list.Count(); i++)
            {
                Console.Write(list[i].ToString()+"\t");
            }
            Console.ReadKey();

上面问题的答案是0,3,7,10;这个问题还有一个类似的兄弟问题就是如何求解同一条直线各个线段覆盖的长度,具体的就将上图的作为参考吧,详细数值看下面代码即可:

  int[] start = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
            int[] end = { 3, 5, 7, 6, 9, 8, 12, 10, 13, 15 };
            int j = 0;
            int sum = end[0] - start[0];
            for (int i = 1; i < start.Length; i++)
            {
                if (start[i] >= end[j])
                {
                    sum += end[i] - start[i];
                    j = i;
                }
                else
                {
                    if (end[i] > end[j])
                    {
                        sum += end[i] - end[j];
                        j = i;
                    }
                }
            }
            Console.WriteLine("总的里程数:" + sum.ToString());
            Console.ReadKey();

 答案是13公里~小算怡情,大算伤身,强算灰灰湮灭,我就小小算算~各位,晚安~

时间: 2024-10-26 11:14:00

算法-贪心算法的相关文章

五大算法—贪心算法

贪心算法 一.基本概念: 所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解. 贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择.必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关. 所以对所采用的贪心策略一定要仔细分析其是否满足无后效性. 二.贪心算法的基本思路: 1.建立数学模型来描述问题. 2.把求解

高级算法——贪心算法(找零问题)

function makeChange(origAmt, coins) {//贪心算法——找零问题 var remainAmt ; if (origAmt % .25 < origAmt) { coins[3] = parseInt(origAmt / .25); remainAmt = origAmt % .25; origAmt = remainAmt; } if (origAmt % .1 < origAmt) { coins[2] = parseInt(origAmt / .1); r

高级算法——贪心算法(背包问题)

贪心算法不能用来解决离散物品问题的原因是我们无法将“ 半台电视” 放入背包. 规则是按照物品价值高低顺序放入背包. function ksack(values, weights, capacity) { var load = 0; var i = 0; var v = 0; while (load < capacity && i < weights.length) { if (weights[i] <= (capacity - load)) { v += values[i

[C++]单源最短路径:迪杰斯特拉(Dijkstra)算法(贪心算法)

1 Dijkstra算法 1.1 算法基本信息 解决问题/提出背景 单源最短路径(在带权有向图中,求从某顶点到其余各顶点的最短路径) 算法思想 贪心算法 按路径长度递增的次序,依次产生最短路径的算法 [适用范围]Dijkstra算法仅适用于[权重为正]的图模型中 时间复杂度 O(n^3) 补充说明 亦可应用于[多源最短路径](推荐:Floyd算法(动态规划,O(n^3))) Dijkstra 时间复杂度:O(n^3) 1.2 算法描述 1.2.1 求解过程(具体思路) 1.2.2 示例 1.2

[C++] 多源最短路径(带权有向图):【Floyd算法(动态规划法)】 VS nX Dijkstra算法(贪心算法)

1 Floyd算法 1.1 Code /** * 弗洛伊德(Floyd)算法: 1 解决问题: 多源最短路径问题 求每一对顶点之间的最短路径 Background: 带权有向图 2 算法思想: 动态规划(DP, Dynamic Programming) 3 时间复杂度: O(n^3) */ #include<stdio.h> #include<iostream> using namespace std; // 1 定义图模型(邻接矩阵表示法)的基本存储结构体 # define Ma

数据结构与算法-贪心算法

#include "pch.h" #include <iostream> #include <stdio.h> int main() { const int RMB[] = { 200, 100, 20, 5, 1 }; const int NUM = 5; int X = 628; int count = 0; for (int i = 0; i < NUM; i++) { int use = X / RMB[i]; count += use; X =

五大常用算法之三贪心算法

贪心算法 贪心算法简介: 贪心算法是指:在每一步求解的步骤中,它要求"贪婪"的选择最佳操作,并希望通过一系列的最优选择,能够产生一个问题的(全局的)最优解. 贪心算法每一步必须满足一下条件: 1.可行的:即它必须满足问题的约束. 2.局部最优:他是当前步骤中所有可行选择中最佳的局部选择. 3.不可取消:即选择一旦做出,在算法的后面步骤就不可改变了. 贪心算法案例: 1.活动选择问题  这是<算法导论>上的例子,也是一个非常经典的问题.有n个需要在同一天使用同一个教室的活动a

Runnable接口和贪心算法

1 Runnable接口 Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现.设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议.激活的意思是说某个线程已启动并且尚未停止. 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口.实际上,Thread实现了Runnable接口. 2 贪心算法 贪心算法把问题分解为几个有顺序的子问题,逐一对子问题进行求解,每一步都是在已求解子问题的基础上求取最优解,是对已求解部分解的一个扩展,直到

活动选择问题(贪心算法vs动态规划)

活动选择问题贪心算法vs动态规划 基础知识 1-1动态规划 1-2贪心算法 1-3贪心算法vs动态规划 活动选择问题描述 活动选择问题最优子结构 活动选择问题算法设计 4-1贪心算法之选择最早结束活动 4-1-1递归贪心算法 4-1-2迭代的方式进行 4-2贪心算法之选择最短时长活动 4-3动态规划方法实现 4-3-1自上而下的实现 4-3-2自下而上的实现 结论 活动选择问题(贪心算法vs动态规划) 1.基础知识 在讲解活动选择问题之前,我们首先来介绍一动态规划和贪心算法的基础知识 1-1.动