[4]贪心算法

贪心算法不从整体最优上考虑,而是在局部最优上做出选择。对于很多问题贪心法不能得到整体最优解,但对于某些特殊的问题,仍然可以得到整体最优解。使用贪心算法应满足这些性质:

①最优子结构性质:一个问题的最优解包含的子问题也是最优的。
②贪心选择性质:整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。

活动安排问题

n个活动的集合E,都需要使用同一资源,活动i有开始时间si和结束时间fi,如果两个活动时间不冲突,那么就是相容的,目标是选择出一些活动,使它们是集合中最多的相容活动。
贪心算法解决这个问题的方式是,先把所有活动按结束时间非减序排序:

从这个序列中选择第一个活动,然后向后循环,发现和最近选择的一个活动相容的活动就立即选择。该算法在排序后只需要O(n)的时间。
活动安排问题的算法很容易,但应证明用这种算法得到的解是整体最优的。

证明该问题的贪心选择性质

先证明有一个最优解以贪心选择开始,在这个问题中也就是去证明存在最优解以完成时间非减序排列后的问题1为开始。假设有一个最优解,以这个序列中的活动k开始而不是活动1,那么因为活动k的完成时间不小于活动1的完成时间,所以这个活动k一定可以用活动1来代替(得到的解是同等优的),因此一定有一个最优解以贪心选择开始。

在第一个活动通过贪心选择得到了以后,原问题缩减成了规模更小的子问题——从f[1]时间开始剩下的问题的活动安排问题。这时做贪心选择,选择的将是与活动1相容的问题中完成时间最早的的一个,记为m。假设有一个最优解,以活动r开始而不是m,因为m已经是最早的了,所以r一定大于m,因此r的完成时间不小于活动m的完成时间,所以这个活动r一定可以用活动m来代替(得到的解是同等优的)。
综上,证明了贪心选择性质。结合该问题的最优子结构性质,知在该问题中贪心算法得到的解一定是最优解。

最优装载问题

和0-1背包问题不同,最优装载问题的目标是装入更多的物体,不涉及价值一说:

最优装载问题的贪心策略是重量最轻者先装入。

证明该问题的贪心选择性质

先证明有一个最优解以贪心选择开始,即证明按重量排列后存在最优解选择了重量最轻的1号物品。假设有一个最优解,在这个序列中从左往右去看选择的第一个物品是k号而不是1号,那么因为k>1,k号物品的重量一定不小于1号物品,所以k号物品可以用1号物品代替,因此一定有一个最优解以贪心选择开始。

而对于接下来要选择的物品,也是一样,如果没有选择2号物品,那么因为1号被选过了,那么选过的物品一定可以用2号物品代替,得到的解是同等优的,所以满足贪心选择性质。

哈夫曼编码问题

哈夫曼编码问题的贪心选择策略是每次选权重最短的两个子树合并成一棵树。

#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
using namespace std;class Node{public:int j;//在数组中的标号int weight;//重量int parent;//双亲编号int L;//左孩子int R;//右孩子//构造函数Node():weight(0),parent(-1),L(-1),R(-1){}//构造函数Node(int w,int p,int l,int r):weight(w),parent(p),L(l),R(r){}//覆写<运算符friend bool operator<(const Node &n1, const Node &n2);//覆写=运算符(赋值)Node& operator=(const Node &r);
};//覆写<运算符
bool operator<(const Node &n1, const Node &n2)
{//反向覆写,以把后面的最大优先队列变成最小堆if(n1.weight>n2.weight)return 1;else if(n1.weight==n2.weight)//相同时用j来判断谁是先输入的if(n1.j<n2.j)return 1;elsereturn 0;elsereturn 0;
}//覆写=运算符(赋值)Node& Node::operator=(const Node &r)
{this->j=r.j;this->weight=r.weight;this->parent=r.parent;this->L=r.L;this->R=r.R;return *this;
}int count;//Case计数
int n;//测试数目
int t;//编码字符的数目
Node *a;//保存这棵树的数组
Node k1,k2;//两个临时用的Node
int *b;//用来存编码串的数组
int m;//编码数组的游标int main()
{scanf("%d",&n);while(n--){scanf("%d",&t);//读入一个数字ta=new Node[2*t-1];//开辟存放树的空间for(int i=0;i<2*t-1;i++)//把每个节点在数组中的标号存进去a[i].j=i;priority_queue<Node> q;//存放Node节点的优先级队列模仿最小堆for(int i=0;i<t;i++){scanf("%d",&a[i].weight);//读入每个字符的出现次数(权重)q.push(a[i]);//push到最小堆里去}for(int i=t;i<2*t-1;i++)//对于后面的每个节点{k1=q.top();//取出一个给k1q.pop();k2=q.top();//再取出一个给k2q.pop();a[i].R=k1.j;//在数组中记录:右儿子是最小的k1a[i].L=k2.j;//在数组中记录:左儿子是次小的k2a[i].weight=k1.weight+k2.weight;//这个节点的权=两个儿子加起来a[k1.j].parent=a[k2.j].parent=i;//在数组中记录:双亲变化//printf("%d ",a[i].weight);q.push(a[i]);//合成后的新节点入堆}/*for(int i=0;i<2*t-1;i++){printf("[%d]weight:%d,parent:%d,L:%d,R:%d\n",a[i].j,a[i].weight,a[i].parent,a[i].L,a[i].R);}*/printf("Case %d\n",++count);//先输出Case计数b=new int[t];//开辟存放编码串的空间:反向存储for(int i=0;i<t;i++)//对于每个待编码的单位{m=0;//编码数组的游标,每次清0printf("%d ",a[i].weight);//先输出weightfor(int j=i;a[j].parent!=-1;j=a[j].parent)//不断向上找直到根节点{if(a[a[j].parent].L==j)//左孩子是jb[m++]=0;else//右孩子是jb[m++]=1;}for(m=m-1;m>=0;m--)//反向输出编码,因为是反向存储printf("%d",b[m]);printf("\n");}printf("\n");delete[] a;delete[] b;}
return 0;
}

贪心算法和动态规划的不同

贪心算法必须满足贪心选择性质,而动态规划不一定。能用贪心算法解决的问题都可以用动态规划来求解。一般来说动态规划是自底向上的,从小的问题得到大的问题的解;而贪心算法是自顶向下的,每次贪心选择都会把问题缩减为规模更小的子问题。

[5]回溯法

先明确问题的解空间的结构是子集树还是排列树,然后从根结点出发,深度优先遍历解空间。如果在当前扩展结点不能再向纵深方向移动,则当前扩展结点成为死结点,这时回退到最近的一个活结点处,并使其成为当前扩展结点。

传送门:回溯法几个经典问题

[6]分支限界法

分支限界法和回溯法主要区别在于对当前扩展结点所采用的扩展方式不同,分支限界法采用广度优先遍历,回溯法采用深度优先遍历。
但是,从活结点表中选取下一扩展结点的方式也可能有所不同:

①FIFO(队列)式分支限界法:就是使用普通的队列,按照广度优先遍历的次序从队列中拿出先放入队列中的结点。
②优先队列式分支限界法:一般是使用覆写了比较运算的堆或者按优先级排序的队列,并不是先进的一定先出,所以不是完全的广度优先。

比如在装载问题中,以(当前载重+剩余所有物品的重量和)为优先级,问优先级队列中结点的变化过程,不妨先画出解空间树:

假设给定背包总容量是25,三个物品重量w1=10,w2=16,w3=9,在图上标注每个可达节点的(当前载重,剩余所有物品的重量和):

所以优先级队列中的变化:

可以看到用这种方式并不是完全的广度优先,但是可以更快的找到一个不错的解。更早的找到不错的解,可以有效地刷新某些Bound限界条件,使得限界条件剪枝剪枝做的更好。例如,如果以重量最大为目标,一个可行的Bound条件是:如果接下来的所有物品加进来的重量都没有当前找到的临时最优解的重量大,这条路就不可能更优,直接剪掉这棵子树。

【算法学习笔记】4:贪心法,回溯法,分支限界法,解空间树剪枝相关推荐

  1. 数据结构—回溯法、子集树、排列树

    文章目录 回溯法 问题的解空间 递归回溯 迭代回溯 子集树与排列树简单介绍 轮船装载问题 0-1背包问题 八皇后问题 整数求和(1) 整数求和(2) 全排列 回溯法 回溯法是一种以深度优先方式系统搜索 ...

  2. 网络流算法学习笔记——最大流问题基本概念和Ford-Fulkerson方法(标号法C++实现)

    屈婉玲<算法设计与分析>第2版第7章网络流算法学习笔记. 基本概念 最大流问题,相当于有从s到t的供水系统,每段路径都有限定流量,除了s.t两地外,每个中间点都不能滞留,从s流入多少,就从 ...

  3. 算法设计与分析-----贪心法

    算法设计与分析-----贪心法(c语言) 一.贪心法 1.定义 2.贪心法具有的性质 1.贪心选择性质 2.最优子结构性质 3.贪心法的算法框架 5.求解活动安排问题 6.求解最优装载问题 二. 贪心 ...

  4. 机器学习knn算法学习笔记使用sklearn库 ,莺尾花实例

    ** 机器学习knn算法学习笔记使用sklearn库 ,莺尾花实例. 具体knn算法是怎样的我这里就不再详细论述.在这里我注意总结我使用knn算法进行一个分类的分析 ** 分析过程 1.前期准备 引入 ...

  5. Python最优化算法学习笔记(Gurobi)

    微信公众号:数学建模与人工智能 github地址:https://github.com/QInzhengk/Math-Model-and-Machine-Learning Python最优化算法学习笔 ...

  6. 数学建模算法学习笔记

    数学建模算法学习笔记 作为建模Man学习数学建模时做的笔记 参考文献: <数学建模姜启源第四版> 网上搜罗来的各种资料,侵删 1.线性预测 levinson durbin算法,自相关什么的 ...

  7. 数据结构与算法学习笔记4:递归+分治法

    数据结构与算法学习笔记4 递归 斐波那契数列 青蛙跳台阶问题 链表倒序打印 分治法 二分查找/折半查找 Binary Search 题目1:快速幂 题目2:如何判断一个数是否为2的次幂 递归 指在函数 ...

  8. Python预测 数据分析与算法 学习笔记(特征工程、时间序列)

    微信公众号:数学建模与人工智能 GitHub - QInzhengk/Math-Model-and-Machine-Learning 第3章 探索规律 3.1 相关分析 相关关系是一种与函数关系相区别 ...

  9. 数据结构与算法学习笔记——图 C++实现

    数据结构与算法学习笔记--图 C++实现 1 概念 2 图的表示方法 3 算法 3.1 拓扑排序 3.2 图的搜索算法 3.2.1 广度优先搜索(BFS) 3.2.2 深度优先搜索(DFS) 3.3 ...

  10. 数学建模学习笔记之评价问题聚类分析法

    数学建模学习笔记之评价问题聚类分析法 物以类聚.人以群分. 聚类分析是一个很大的概念,显然根据分类的依据不同会出现很多很多聚类的方法.例如K-Means .Sequential Leader.Mode ...

最新文章

  1. js控制网页滚动条往下滚动
  2. 浅谈Java中的Set、List、Map的区别
  3. 撕掉“丑”的标签,体素是如何让游戏更有趣的?
  4. java课设电子门禁_中控门禁pullSdk Java demo 中控智慧门禁系统 - 下载 - 搜珍网
  5. 我的WCF之旅(10):如何在WCF进行Exception Handling
  6. c语言从入门到精通的几个阶段
  7. 从零开始打造自己的PHP框架——第3章
  8. matlab图像处理中的错误--调用imhist报错
  9. 关于Vue中v-if 和 v-for一起使用
  10. 信息系统基础知识(笔记)
  11. 使用python裁剪图片
  12. git rebase 命令 常用_git命令之git rebase 的用法
  13. 2022-2028年中国淄博房地产行业市场发展潜力及投资策略研究报告
  14. CRM实施阻力之独行侠作风
  15. 全网最全获取设计灵感创意的网站
  16. VMware是什么?
  17. 来认识一下哥德尔不完备定理
  18. Centos逻辑卷扩容、合并
  19. 数据结构第1章绪论相关练习题
  20. “打工皇帝”唐骏语录

热门文章

  1. 机票预订系统的数据流程图及实体联系图
  2. 计算机无法读取智能卡,电脑智能卡读卡器驱动程序丢失怎么办?如何重新安装智能卡服务?...
  3. 8月24日科技联播:特斯拉回应苹果“疯狂挖人”,对方比我们有钱100倍
  4. VB6.0调用WebService
  5. 什么是短连接,如何用 Python 生成短连接?
  6. 一文讲透高速缓存原理
  7. ddos应急处理_DDoS攻击应急体系知多少?
  8. linux给文件夹图标,Linux 如何在启动器中自定义图标
  9. WPS Excel+windows批处理批量重排序文件夹
  10. 武汉理工计算机保研去华科,武汉理工大学2021届保研率14.9%,主要保研本校、武大、华科...