贪心算法

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解 。

贪心算法不是对所有问题都能得到体最优解,关键是整贪心策略的选择

贪心算法一般按如下步骤进行:

①建立数学模型来描述问题   。

②把求解的问题分成若干个子问题   。

③对每个子问题求解,得到子问题的局部最优解   。

④把子问题的解局部最优解合成原来解问题的一个解   。

贪心算法实际应用---零钱找回问题

这个问题在我们的日常生活中很普遍。

假设1元、2元、5元、10元、20元、50元、100元的纸币分别有

c0, c1, c2, c3, c4, c5, c6张。现在要用这些钱来支付K元,至少要用多少张纸币?

用贪心算法的思想,很显然,每一步尽可能用面值大的纸币即可。在日常生活中我们自然而然也是这么做的。在程序中已经事先将Value按照从小到大的顺序排好。

#include <iostream>#include <math.h>using namespace std;int single_money[7]={1,2,5,10,20,50,100};int number_money[7]={2,5,1,3,4,0,4};//每种面值使用贪心后的张数int count[7]={};int total_count;int tanxin(int money){if(money>=0){for(int i=6;i>=0;i--){count[i]=min(number_money[i],money/single_money[i]);money=money-count[i]*single_money[i];}return 0;}else{return money;}}int main(){int money;cout<<"please input the amount of money";cin>>money;if(!tanxin(money)){cout<<"贪心最优结果为:"<<endl;for(int j=6;j>=0;j--){cout<<single_money[j]<<"元:"<<count[j]<<"张"<<endl;}}else{cout<<"ops,wrong number";}return 0;}

贪心算法实际应用---活动安排问题

活动选择问题:这是《算法导论》上的例子,也是一个非常经典的问题。

n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。

每个活动ai都有一个开始时间si和结束时间fi 。一旦被选择后,活动ai就占据半开时间区间[si,fi)

如果[si,fi][sj,fj]互不重叠,aiaj两个活动就可以被安排在这一天。

该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。

#include <iostream>#include <algorithm>using namespace std;//定义活动的集合,Act 为抽象数据类型名,activity 为实例数据//结构体struct Act{int start;int end;} activity[100];int N;//活动的个数//给出了排序方法                                                                                                                                                                                                                                                                          bool cmp(Act a,Act b){return a.end<b.end;}int greedy(){int num=0;//要在排序之后实现for (int i=0,j = i+1;i<N;++j){if (activity[j].start > activity[i].end ){i = j;num++;}}return num;}int main(int argc,char** argv){//问题的初始化cout<<"The total num of activities:";cin>>N;cout<<"Please input the start and end time of each activity:";for (int i = 0;i<N;++i){cin>>activity[i].start;cin>>activity[i].end;}//将活动按结束时间排序,cmp为排序标准,sort也可以只有两个参数sort(activity,activity+N,cmp);//输出结果int res = greedy();cout<<"The maximum activities can be hold is "<<res;system("pause");return 0;}

经典算法中的贪心

单源路径中的Djikstra算法

注意核心:1.一旦一个点已经被选定,就代表它到起点的最短距离已经确定了,不会再更改

2.每次比较的距离是从起点出发的路径,而不是单独比较以选定点为起点的边

下面例题,以D为起点

第一步,D到C最短,将C加入集合S

此时集合S有C,D

第二步,距离分别是,<D,E>=4,<D,C,F>=9,<D,C,E>=8,<D,C,B>=13

将E点加入S

第三步,距离分别为,<D,C,F>=9,<D,C,B>=13,<D,E,F>=6,<D,E,G>=12

将F加入S

第四步,距离分别为,<D,C,B>=13,<D,C,F,A>=25,<D,C,F,G>=18,<D,C,F,B>=16,<D,E,G>=12,<D,E,F,A>=22,<D,E,F,B>=13

将G加入S

第五步,距离分别为,<D,C,B>=13,<DE,F,A>=22,<D,E,G,A>=26

将B加入S

第六步,<D,C,B,A>=25,<D,E,F,A>=22,<D,E,G,A>=26

将A加入S

#include<stdio.h>#include<string.h>#define inf 0x3f3f3f3fint map[110][110],dis[110],visit[110];/*关于三个数组:map数组存的为点边的信息,比如map[1][2]=3,表示1号点和2号点的距离为3dis数组存的为起始点与每个点的最短距离,比如dis[3]=5,表示起始点与3号点最短距离为5visit数组存的为0或者1,1表示已经走过这个点。*/int n,m;int dijstra()
{int i,j,pos=1,min,sum=0;memset(visit,0,sizeof(visit));//初始化为.,表示开始都没走过for(i=1; i<=n; ++i){dis[i]=map[1][i];}visit[1]=1;dis[1]=0;for(i=1; i<n; i++){min=inf;for(j=1; j<=n; ++j){if(visit[j]==0&&min>dis[j]){min=dis[j];pos=j;}}visit[pos]=1;//表示这个点已经走过for(j=1; j<=n; ++j){if(visit[j]==0&&dis[j]>dis[pos]+map[pos][j])//更新dis的值dis[j]=dis[pos]+map[pos][j];}}return dis[n];}int main(){int i,j;while(~scanf("%d%d",&n,&m),n||m)//n表示n个点,m表示m条边{for(i=1; i<=n; ++i){for(j=1; j<=n; ++j){map[i][j]=inf;//开始时将每条边赋为最大值}}int a,b,c;for(i=1; i<=m; ++i){scanf("%d%d%d",&a,&b,&c);if(c<map[a][b])//防止有重边map[a][b]=map[b][a]=c;}int count=dijstra();printf("%d\n",count);}     return 0;}

最小生成树Prim算法

lowcost[i]:表示以i为终点的边的最小权值,当lowcost[i]=0说明以i为终点的边的最小权值=0,也就是表示i点加入了MST

mst[i]:表示对应lowcost[i]的起点,即说明边<mst[i],i>是MST的一条边,当mst[i]=0表示起点i加入MST

第一步,以V1为起点,lowcost[2]=6,lowcost[3]=1,lowcost[4]=5

Mst[2]=1,mst[3]=1,mst[4]=1

MST中有V1,再加入V3

第二步,经过比较后更新,比如<v1,v2>=6 > <v3,v2>=5,所以low cost[v2]=5.

Lowcost[2]=5,lowcost[3]=0,lowcost[4]=5,lowcost[5]=6,

Lowcost[6]=4

Mst[2]=3,mst[3]=0,mst[4]=1,mst[5]=3,mst[6]=3

MST 中有V1,V3,再加入V6

第三步,经过比较后,更新,Lowcost[2]=5,lowcost[3]=0,lowcost[4]=2,lowcost[5]=6,

Lowcost[6]=0

Mst[2]=3,mst[3]=0,mst[4]=6,mst[5]=3,mst[6]=0

MST中有V1,V3,V6,再加入V4

第四步,经过比较后,更新,Lowcost[2]=5,lowcost[3]=0,lowcost[4]=0,lowcost[5]=6,

Lowcost[6]=0

Mst[2]=3,mst[3]=0,mst[4]=0,mst[5]=3,mst[6]=0

MST中有V1,V3,V6,V4,再加入V2

第五步,经过比较后,更新,Lowcost[2]=0,lowcost[3]=0,lowcost[4]=5,lowcost[5]=3,

Lowcost[6]=0

Mst[2]=0,mst[3]=0,mst[4]=0,mst[5]=2,mst[6]=0

MST中有V1,V3,V6,V4,V2,再加入V5

可得生成树如上。注意此算法考虑的不是从出发点到该点的距离,而是考虑以该点为终点的权值,以及记住该边的起始点。

#include<iostream>#include<fstream>using  namespace std;#define MAX 100#define MAXCOST 0x7fffffffint graph[MAX][MAX];//距离表格//lowcost[i]:表示以i为终点的边的最小权值,当lowcost[i]=0说明以i为终点的边的最小权值=0,也就是表示i点加入了MST//mst[i]:表示对应lowcost[i]的起点,即说明边<mst[i],i>是MST的一条边,当mst[i]=0表示起点i加入MSTint prim(int graph[][MAX], int n){int lowcost[MAX];int mst[MAX];//int i, j, min, minid, sum = 0;for (i = 2; i <= n; i++){lowcost[i] = graph[1][i];mst[i] = 1;}mst[1] = 0;for (i = 2; i <= n; i++){min = MAXCOST;minid = 0;for (j = 2; j <= n; j++){if (lowcost[j] < min && lowcost[j] != 0){min = lowcost[j];minid = j;}}cout << "V" << mst[minid] << "-V" << minid << "=" << min << endl;sum += min;lowcost[minid] = 0;for (j = 2; j <= n; j++){if (graph[minid][j] < lowcost[j]){lowcost[j] = graph[minid][j];mst[j] = minid;}}}return sum;}int main(){int i, j, k, m, n;int x, y, cost;ifstream in("input.txt");in >> m >> n;//m=顶点的个数,n=边的个数//初始化图Gfor (i = 1; i <= m; i++){for (j = 1; j <= m; j++){graph[i][j] = MAXCOST;}}//构建图Gfor (k = 1; k <= n; k++){in >> i >> j >> cost;graph[i][j] = cost;graph[j][i] = cost;}//求解最小生成树cost = prim(graph, m);//输出最小权值和cout << "最小权值和=" << cost << endl;system("pause");return 0;}

最小生成树 Kruskal算法(加边法)

与Prim算法不同,Kruskal算法是保留点,一条一条加边

第一步,选取<v0,v4>

第二步,选取<v1,v2>

第三步,选取<v1,v5>

第四步,选取<v1,v5>

依次类推,直到所有点都访问到

#include <iostream>#include <stdio.h>#include <stdlib.h>using namespace std;int parent[10];int n,m;int i,j;struct edge{int u,v,w; //边的顶点,权值}edges[10];//初始化并查集void UFset(){for(i=1; i<=n; i++) parent[i] = -1;}//查找i的跟int find(int i){int temp;//查找位置for(temp = i; parent[temp] >= 0; temp = parent[temp]);//压缩路径while(temp != i){int t = parent[i];parent[i] = temp;i = t;}return temp;}//合并两个元素a,bvoid merge(int a,int b){int r1 = find(a);int r2 = find(b);int tmp = parent[r1] + parent[r2]; //两个集合节点数的和if(parent[r1] > parent[r2]){parent[r1] = r2;parent[r2] = tmp;}else{parent[r2] = r1;parent[r1] = tmp;}}void kruskal(){int sumWeight = 0;int num = 0;int u,v;UFset();for(int i=0; i<m; i++){u = edges[i].u;v = edges[i].v;if(find(u) != find(v)){ //u和v不在一个集合printf("加入边:%d %d,权值: %d\n", u,v,edges[i].w);sumWeight += edges[i].w;num ++;merge(u, v); //把这两个边加入一个集合。}}printf("weight of MST is %d \n", sumWeight);}//比较函数,用户排序int cmp(const void * a, const void * b){edge * e1 = (edge *)a;edge * e2 = (edge *)b;return e1->w - e2->w;}int main() {scanf("%d %d", &n, &m);for(i=0; i<m; i++){scanf("%d %d %d", &edges[i].u,  &edges[i].v,  &edges[i].w);}qsort(edges, m, sizeof(edge), cmp);kruskal();return 0;}//kruskal 算法也是贪心,考虑的是边

贪心算法 看这一篇就够了相关推荐

  1. Dropout、梯度消失/爆炸、Adam优化算法,神经网络优化算法看这一篇就够了

    作者 | mantch 来源 | 知乎 1. 训练误差和泛化误差 对于机器学习模型在训练数据集和测试数据集上的表现.如果你改变过实验中的模型结构或者超参数,你也许发现了:当模型在训练数据集上更准确时, ...

  2. 如何应对大数据分析工程师面试Spark考察,看这一篇就够了

    作者丨斌迪.HappyMint 来源丨大数据与人工智能(ID:ai-big-data) [导读]本篇文章为大家带来spark面试指南,文内会有两种题型,问答题和代码题,题目大部分来自于网络上,有小部分 ...

  3. 最优化算法对偶单纯形法的matlab实现(对偶单纯形法看这一篇就够了)

    文章目录 前言 一.单纯形法表格 1.1可立即读出最优解和最优值的表格具备的特点 二.对偶单纯形法的步骤(流程图) 三.对偶单纯形法的matlab实现 3.1对偶单纯形法matlab代码 3.2测试例 ...

  4. api网关选型_如何轻松打造百亿流量API网关?看这一篇就够了(下)

    如何轻松打造百亿流量API网关?看这一篇就够了(上) 上篇整体描述了网关的背景,涉及职能.分类.定位环节,本篇进入本文的重点,将会具体谈下百亿级流量API网关的演进过程. 准备好瓜子花生小板凳开始积累 ...

  5. 深度好文:云网络丢包故障定位,看这一篇就够了~

    深度好文:云网络丢包故障定位,看这一篇就够了~ https://mp.weixin.qq.com/s/-Q1AkxUr9xzGKwUMV-FQhQ Alex 高效运维 今天 来源:本文经授权转自公众号 ...

  6. minio存储类型 归档管理页面_软件定义存储,看这一篇就够了

    minio存储类型 归档管理页面_软件定义存储,看这一篇就够了_婷婷与li的博客-CSDN博客 请看链接 文章来源于TaoCloud ,作者刘爱贵 1.SDS科普 SDS(Software Defin ...

  7. 聊聊Java8之后的JDK升级内容(看这一篇就够了)

    聊聊Java8之后的JDK升级内容(看这一篇就够了) 背景 从 JDK 8 到 JDK 17 的新特性 JDK8 回顾 JDK9 JDK10 JDK11 JDK12 JDK13 JDK14 JDK15 ...

  8. 面试被问到 ConcurrentHashMap答不出 ,看这一篇就够了!

    本文汇总了常考的 ConcurrentHashMap 面试题,面试 ConcurrentHashMap,看这一篇就够了!为帮助大家高效复习,专门用"★ "表示面试中出现的频率,&q ...

  9. 如何快速找到志同道合的人?看这一篇就够了

    如何快速找到志同道合的人?看这一篇就够了 一.前言 参加工作也有挺长一段时间了,一直以来自己也很希望可以真正为自己打拼一片天地,这应该也是大部分中产白领很希望做的事,有些人成功了,有些人在路上,而有些 ...

  10. python装饰器功能是冒泡排序怎么做_传说中Python最难理解的点|看这完篇就够了(装饰器)...

    https://mp.weixin.qq.com/s/B6pEZLrayqzJfMtLqiAfpQ 1.什么是装饰器 网上有人是这么评价装饰器的,我觉得写的很有趣,比喻的很形象 每个人都有的内裤主要是 ...

最新文章

  1. fitype拟合多参数函数和遗传算法拟合多参数函数
  2. docker 安装nacos_「Java Spring Cloud 实战之路」 使用nacos配置网关
  3. python简单超级马里奥游戏下载_python 实现超级玛丽游戏
  4. OpenCV:Adaboost训练时数据扩增
  5. 推动Windows的限制:句柄
  6. JWT token信息保存
  7. react sql格式化_为SQL Server数据库损坏做准备; 初步React与分析
  8. 简单说说JAVA的String和byte[]的关系
  9. tf.slim构建vgg16和resnet网络实现图像分类,亲测准确率99%
  10. Ubuntu系统下载工具的推荐
  11. 墨画子卿第一章第1节
  12. 莫 言------------- 我们的荆轲
  13. 计算机视觉及色彩空间RGB,HSV,HLS,Lab,LMS,XYZ,CMYK
  14. 使用C语言来访问ARM寄存器的语法
  15. matlab运动物体仿真,运动目标跟踪的多模型算法仿真程序
  16. win10升级后蓝牙不见了,设备管理器里没有,多了个串行控制器里的未知USB设备?...
  17. 51单片机+DS18B20+数码管显示+串口通讯+Proteus仿真
  18. [DataAnalysis]多元线性回归深入浅出-案例+模型假设+参数估计方法+模型评判方法+变量选择+多重共线性问题
  19. MATALAB绘制色图变换和Voronoi图
  20. 输入分数,判定成绩等级 -90 以上 优秀 70 以上良好 60 及格 60 以下不及格(if和switch两种写法)

热门文章

  1. PDF文件限制密码如何解除
  2. 第三天---网络系统硬件
  3. MySQL数据库日志的查看
  4. 学习笔记9--汽车线控系统技术
  5. idea 导入 android项目以及自带AVD模拟器的使用
  6. 【电源芯片】TPS63020升降压芯片-电池放电
  7. 数字信号处理(三)离散时间信号的Z变换
  8. 208个地级市和31个省市城乡泰尔指数(2010-2019年)
  9. 简述神经网络的优点和缺点,人工神经网络优缺点
  10. 简述电子计算机发展五个阶段,简述erp发展的5个阶段