【算法基础】----贪心算法

来源:互联网 发布:mac如何删除用户 编辑:程序博客网 时间:2024/04/29 07:36

贪心算法是常见的基础算法,它在求解问题时总想用当前看来最好的方法去实现,而到了下一步,再用下一步时最好的方法来解决,因此有了贪心的名字。此方法不从整体去考虑,仅是在某种意义上的局部最优求解。虽然贪心算法不是对所有的问题都能得到整体最优解,但是面对范围相当广泛的很多问题时,能产生整体最优解或是整体最优解的高度近似解,因此可见贪心算法只是追去一定范围内的最优。

1. 贪心算法的基础



贪心算法在解决一个问题时,通常会从某一个初始解出发,逐步逼近给定的目标,以便尽快求出更好的解。

当达到算法中的某一步不能在继续进行下去的时候,就停止算法,给出一个近似解。由贪心算法的特点和思路可以看出,贪心算法存在以下3个问题。

(1).不保证最后得解是最优的(实际上它从不考虑最后得结果)

(2).不能用来求最大或最小解的问题

(3).只能满足某些约束条件的可行解的范围

而通常情况下,贪心算法的思路如下:

(1).建立数学模型来描述问题

(2).将求解的问题分解为若干范围较小的子问题

(3).对每一子问题求解,得到子问题的局部最优解

(4).把子问题的局部最优合并成原问题的局部最优解

下面我们通过两个例子来描述贪心算法


1. 找零方案

在现实生活中,我们买东西经常需要找零,而商店找零的方法通常是优先找面额大的,再找小面额的。因为我们永远都不是商店的最后一个顾客,因此商店为了保证下一个顾客依然有零钱可以找,会尽可能的把面额大的找给我们,而把零钱留给自己。

人民币有100、50、20、10、5、1、0.5、0.2、0.1(单位:元)等多种面额,设计一个找零算法,使得面值大的尽可能多的被找。

#include <iostream>using namespace std ;int main(void) {        int i ;        float money ;        float x[9] = {100 , 50 , 20 , 10 , 5 , 1 , 0.5 , 0.2 , 0.1} ;        cin >> money ;        for(i = 0 ; i < 9 ; ++ i) {                while(money >= x[i]) {                        money -= x[i] ;                        cout << x[i] << "  " ;                }        }        return 0 ;}





上面只是一个简单的例子,下面我们来详细的讨论一下装箱问题

假设有编号为0,1,2.....n-1的n中物品,体积分别为v0,v1,v2......v(n-1),现需要将这些物品装进容积为V的若干箱子中,且箱子的体积不会小于任一物品。不同的装法可能。需要数量不同的箱子,现在我们需要用尽可能少的箱子装下所有的物品。

例:箱子的容量为10,有四个物品,体积分别为6,7,4,3,如果按照6->7->4->3的顺序,需要3个箱子,而如果按照6->4->7->3的顺序,只需要两个箱子。

选择数据结构

数据结构的选择关系到算法的高效与否。

存储链式结构,不涉及元素的进出,排除了栈和队列。有数组和链表可供选择,而我们在装箱问题中选择链表的原因有一下两点:

1.建立数据结构时,我们事先并不知道需要多少箱子,即无法确定元素的个数。

2.在算法的运行中,我们一旦确定了物品装进哪个箱子,就需要将物品和箱子建立某中内存上的联系,使得通过箱子可以找到其中的物品。

而数组显然不具备以上功能,因此我们选择链表。

typedef struct gNode {                  //structs array        int num ;        int gV ;}gNode ;typedef struct ElemNode {               //物品节点        int gV ;        int gNum ;        struct ElemNode * next ;        //节点中指向下一个物品的指针}ElemNode ;typedef struct gBox {                   //箱子节点        int V ;                         //箱子的容积        ElemNode * nextNode ;           //箱子节点中指向其中物品的指针        struct gBox * nextBox ;         //箱子节点中指向下一个箱子的节点}gBox ;

最终程序运行时的数据结构应该是这样


实际代码如下:


#include <stdio.h>#include <stdlib.h>const int maxV = 10 ;typedef struct gNode {                  //structs array        int num ;        int gV ;}gNode ;typedef struct ElemNode {               //物品节点        int gV ;        int gNum ;        struct ElemNode * next ;        //节点中指向下一个物品的指针}ElemNode ;typedef struct gBox {                   //箱子节点        int V ;                         //箱子的容积        ElemNode * nextNode ;           //箱子节点中指向其中物品的指针        struct gBox * nextBox ;         //箱子节点中指向下一个箱子的节点}gBox ;gBox * Pack(gBox * hB , gNode * hG , int num) {        int i ;        gBox * t , * iBox , * newBox;        ElemNode * newNode = NULL , * findEnd = NULL ;        hB = t = (gBox *)malloc(sizeof(gBox)) ;                 //拿出第一个物品,必定打开一个箱子        t -> V = maxV ;                                         //        t -> nextNode = NULL ;                                  //初始化箱子        t -> nextBox = NULL ;                                   //        for(i = 0 ; i < num ; ++ i) {                      newNode = (ElemNode *)malloc(sizeof(ElemNode)) ;        //每一个物品,都需要分配一块内存                newNode ->gV = (hG+i)->gV ;                newNode ->gNum = (hG+i)->num ;                newNode ->next = NULL ;//从第一个物品开始装,等到所有的物品都遍历完,说明装箱结束。                for(iBox = hB ; iBox ; iBox = iBox ->nextBox) {                                                //每拿到一个物品,都要从第一个箱子开始遍历,直到找到一个箱子或者现有的箱子都没法装下                        if((hG + i) -> gV < iBox ->V) {         //如果当前箱子的剩余容积大于物品的体积,可以放                                findEnd = iBox ->nextNode ;                             //使用findEnd指针来找到物品链的末尾                                while(findEnd ->next || findEnd) {                      //使用或运算符可以兼容箱子中有物品或没物品                                        findEnd = findEnd -> next ;                     //两种情况                                }                                findEnd ->next = newNode ;                                iBox ->V -= newNode ->gV ;                        }                                        }                newBox = (gBox *)malloc(sizeof(gBox)) ;                 //如果当前所有箱子都不符合条件,创建一个新的箱子节点                newBox ->V = maxV ;                                     //并初始化                newBox ->nextNode = NULL ;                                                          newBox ->nextBox = NULL ;                t = t ->nextBox = newBox ;              //然后将新的箱子挂在箱子链的末尾                t ->nextNode = newNode ;                //最后将新的物品挂在新的箱子上        }}void Display(gBox * hBox) {        int i = 1 ;        ElemNode * travelNode = NULL ;        gBox * travelBox = NULL ;        for(travelBox = hBox ; travelBox ; travelBox = travelBox ->nextBox) {                printf("第%d个箱子中装有物品:" , i ++) ;                travelNode = travelBox ->nextNode ;                while(travelNode) {                        printf("%4d" , travelNode ->gNum) ;                }                printf("\n") ;        }}int main(void) {        int num , i ;        printf("please input the number of boxes:") ;        scanf("%d" , num) ;        gNode * hG = (gNode *)malloc(num * sizeof(gNode)) ;             //创建结构体数组,用来存储物品信息        for(i = 0 ; i < num ; ++ i) {                (hG+i)->num = i ;                printf("Input No.%d node:" , i) ;                scanf("%d" , &(hG+i)->gV ) ;        }        gBox * hBox = NULL ;        hBox = Pack(hBox , hG , num) ;        Display(hBox) ;        return 0 ;}


0 0
原创粉丝点击