贪心算法小结

article/2025/9/12 19:24:10

目录

贪心算法

例题

活动安排问题

背包问题

删数问题

多处最优服务次序


贪心算法

在求最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解,这种求解方法就是贪心算法。

贪心算法不是从整体上考虑问题,而是在每一步选择中都采取在当前状态下最优的选择,即希望通过问题的局部最优解求出整个问题的最优解。

这种策略是一种很简洁的方法,对许多问题它能产生整体最优解,但不能保证总是有效,因为它不是对所有问题都能得到整体最优解。

如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。

利用贪心策略解题,需要解决两个问题:

  • (1)该题是否适合于用贪心策略求解;
  • (2)如何选择贪心标准,以得到问题的最优/较优解。

例题

活动安排问题

1.描述

设有n个活动的集合E={1,2,…,n},每个活动都要使用同一资源,如演讲会场等,而在同一时间段内只有一个活动能使用这一资源。

每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si<fi。如果选择了活动i,则在[si ,fi )内占用资源。

若区间[si ,fi )与区间[sj,fj )不相交,则称活动i与活动j是相容的。

活动安排问题就是在所给的活动集合中选出最大的相容活动子集合。

此时追求的最优是在最短的时间内安排最多的活动

2.思路

按照起止时间排序:有可能遇到初始时间很早,但结束时间很晚的活动。不合适

按照终止时间排序:优先选择较早终止且不与前面活动相交的活动

3.代码

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
struct action{int s;//起始时间int f;//结束时间int index;//活动的变化
};bool cmp(const action &a,const action &b){if(a.f<=b.f)return true;return false;
}void GreedySelector(int n,action a[],bool b[]){b[1]=true;//选中排序后的第一个活动int preEnd=1;//记录最近一次加入集合b的活动for(int i=2;i<=n;i++)if(a[i].s>=a[preEnd].f){b[i]=true;preEnd=i;}}
int main()
{action a[1001];int n;scanf("%d",&n);bool b[n+1];for(int i=1;i<=n;i++){scanf("%d%d%d",&a[i].s,&a[i].f,&a[i].index);b[i]=false;}sort(a,a+n+1,cmp);GreedySelector(n,a,b);for(int i=1;i<=n;i++)if(b[i])printf("%d\n",a[i].index);return 0;
}

背包问题

1.描述

给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量 ,价值wi (1≤i≤n),要求把物品装满背包,且使背包内的物品价值最大。

  • 如果物品不可以分割,称为0—1背包问题(动态规划),可以参考我另一篇博客
  • 如果物品可以分割,则称为背包问题(贪心算法)。

2.思路

有3种方法来选取物品:

  • (1)当作0—1背包问题,用动态规划算法,获得最优值220;
  • (2)当作0—1背包问题,用贪心算法,按性价比从高到底顺序选取物品,获得最优值160。由于物品不可分割,剩下的空间白白浪费,不是最优。
  • (3)当作背包问题,用贪心算法,按性价比从高到底的顺序选取物品,获得最优值240。由于物品可以分割,剩下的空间装入物品3的一部分,而获得了更好的性能。

3.代码

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
struct bag{int w;//物品的重量int v;//物品的价值double c;//性价比double x;//此物品装入背包的量int index;
};bool cmp(bag a,bag b){if(a.c>=b.c)return true;return false;//return a.c>=b.c;
}double pack(int n,bag a[],double c){double cleft=c;//背包的剩余容量int i=0;double b=0;//装入物品的总价值//背包可以直接装入一个物品iwhile(i<n&&a[i].w<cleft){cleft-=a[i].w;b+=a[i].v;a[a[i].index].x=1.0;i++;}//把物品分割后装满背包if(i<n){a[a[i].index].x=1.0*cleft/a[i].w;b+=a[a[i].index].x*a[i].v;}return b;
}int main()
{bag a[1001];int n,c;scanf("%d%d",&n,&c);for(int i=0;i<n;i++){scanf("%d%d%lf%d",&a[i].w,&a[i].v,&a[i].c,&a[i].index);a[i].x=0;}sort(a,a+n,cmp);printf("%f\n",pack(n,a,c));for(int i=0;i<n;i++)if(a[i].x!=0)printf("%d:%f\n",a[i].index,a[i].x);return 0;
}

删数问题

1.描述

给定n位正整数a,去掉其中任意k≤n个数字后,剩下的数字按原次序排列组成一个新的正整数。对于给定的n位正整数a和正整数k,设计一个算法找出剩下数字组成的新数最小的删数方案。

输入:第1行是1个正整数a,第2行是正整数k。

输出:对于给定的正整数a,编程计算删去k个数字后得到的最小数。

2.思路

n位数a,n可能特别大,因此可以用字符串存放,a表示为x1x2… xn,要删去k位数,使得剩下的数字组成的整数最小。
将该问题记为T,最优解A=xi1 xi2…xim (i1<i2<..<im,m=n-k),在删去k个数后剩下的数字按原次序排成的新数,其最优值记为N。

采用最近下降点优先的贪心策略:即x1<x2<... <xi-1<xi,如果xi+1<xi(下降点),则删去xi,即得到一个新的数且这个数为n-1位中最小的数N,可表示为x1x2…xi-1 xi+1...xn。

显然删去1位数后,原问题T变成了对n- 1位数删去k- 1个数的新问题T'
新问题和原问题性质相同,只是问题规模由n减小为n-1,删去的数字个数由k减少为k-1。
基于此种删除策略,对新问题T’,选择最近下降点的数继续进行删除,直至删去k个数为止。

3.代码

#include <iostream>
#include <cstring>
using namespace std;int main()
{string a;int k,i;cin>>a>>k;if(k>=a.size())a.erase();elsewhile(k>0){i=0;while(a[i]<=a[i+1])i++;if(i<a.size()-1){//cout<<"a:"<<a<<endl;a.erase(i,1);//取出a[i]k--;//针对12345这种情况,删5-4-3……}else if(i == a.size()-1){a.erase(i,1);k--;}//cout<<"k:"<<k<<endl;}while(a.size()>1&&a[0]=='0')a.erase(0,1);cout<<a<<endl;return 0;
}


 

多处最优服务次序

1.描述

设有n个顾客同时等待一项服务,顾客i需要的服务时间为ti,1≤i≤n,共有s处可以提供此项服务。应如何安排n个顾客的服务次序才能使平均等待时间达到最小?平均等待时间是n个顾客等待服务时间的总和除以n。

给定的n个顾客需要的服务时间和s的值,编程计算最优服务次序。

输入:第一行有2个正整数n和s,表示有n个顾客且有s处可以提供顾客需要的服务。接下来的一行中,有n个正整数,表示n个顾客需要的服务时间。

输出:最小平均等待时间,输出保留3位小数。

2.思路

假设原问题为T,并已经知道某个最优服务序列,即最优解为A={t1,t2....tn,其中ti为第i个用户需要的服务时间,则每个用户等待时间T为:
T1=t1;
T2=t1 + t2;
Tn=t1 + t2+...+tn
那么总的等待时间,即最优值N为:
N=nt1 + (n - 1)t2+…+2tn-1+tn
平均等待时间是n个顾客等待时间的总和除以n,故本题实际上就是求使顾客等待时间的总和最小的服务次序。

贪心策略:对服务时间最短的顾客先服务。

首先对需要服务时间最短的顾客进行服务,即做完第一次选择后,原问题T变成了需对n-1个顾客服务的新问题T’。 新问题和原问题相同,只是问题规模由n减小为n-1。

3.代码

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;//顾客等待的队列为client,提供服务的窗口s个
double greedy(int client[],int s,int n){//服务窗口的顾客等待时间int service[s+1];//服务窗口顾客等待时间的总和int sum[s+1];//按顾客的服务时间升序排序sort(client,client+n);//初始化memset(service,0,sizeof(service));memset(sum,0,sizeof(sum));//贪心算法int i=0;//顾客的指针int j=0;//窗口的指针while(i<n){service[j]+=client[i];sum[j]+=service[j];i++;j++;if(j==s)j=0;}double t=0;for(i=0;i<s;i++)t+=sum[i];t/=n;return t;
}int main()
{int client[1000];int s,n;scanf("%d%d",&n,&s);//顾客数,窗口数for(int i=0;i<n;i++)scanf("%d",&client[i]);printf("%f",greedy(client,s,n));return 0;
}


http://chatgpt.dhexx.cn/article/yutHwNn3.shtml

相关文章

贪心算法模板及详解

一、.活动选择问题 二、钱币找零问题 三、再论背包问题 四、多机调度问题 五、小船过河问题 六、区间覆盖问题 七、销售比赛问题 八、Huffman编码 九、Dijkstra算法 十、最小生成树算法 贪心算法的定义 贪心算法是指在对问题求解时&#xff0c;总是做出在当前看来是最…

贪心算法例题

贪心算法经典例题解析 贪心法&#xff1a;遵循某种规律&#xff0c;不断贪心的选取当前最优策略的算法设计方法。 例一&#xff1a;分糖果 已知一些孩子和一些糖果&#xff0c;每个孩子有需求因子g&#xff0c;每个糖果有大小s&#xff0c;当某个糖果的大小s > 某个孩子的需…

贪心算法(Java)

贪心算法 文章目录 贪心算法0、写在前面1、贪心算法的基本要素1.1 贪心选择性质1.2 最优子结构性质1.3 贪心算法与动态规划算法的差异 2、贪心算法的特点3、贪心法的正确性证明4、活动安排问题4.1 问题描述4.2 贪心法的设计思想4.3 两个反例 5、代码6、效率7、实例8、参考 0、写…

贪心算法(Java版本)

一、贪心算法 1、算法描述 贪心算法&#xff08;Greedy algorithm&#xff09;&#xff0c;又叫做贪婪算法。 在对问题求解时&#xff0c;不从整体考虑&#xff0c;而是从问题的某一个初始解出发&#xff0c;每一步选择中都采取在当前状态下最好或最优的选择&#xff08;局部…

Java贪心算法

1.Java贪心算法 1.1 贪心算法介绍 贪心算法是指在对问题进行求解时&#xff0c;在每一步选择中都采取最好或者最优(即最有利)的选择&#xff0c;从而希望能够导致结果是最好或者最优的算法贪心算法所得到的结果不一定是最优的结果(有时候会是最优解)&#xff0c;但是都是相对近…

C语言贪心算法

点击蓝字 关注我们 因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享 来源于网络&#xff0c;侵删 01 基本概念 贪心算法是指在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#…

python贪心算法

文章目录 贪心算法1、分发饼干问题&#xff08;力扣455&#xff09;2、无重叠区间(力扣435)3、分发糖果&#xff08;力扣135&#xff09;4、种花问题&#xff08;力扣605&#xff09;5、用最少数量的箭引爆气球&#xff08;力扣452&#xff09;6、划分字母区间&#xff08;力扣…

算法-贪心算法

贪心算法 基本概念算法思想贪心算法就像周六晚上的动画片一样可遇不可求贪心解题步骤序列问题53. 最大子数组和 跳跃游戏55. 跳跃游戏跳跃游戏 II 分发糖果 基本概念 贪心算法又称贪婪算法&#xff0c;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。换句话说&am…

三大算法之三:贪心算法及其例题详解

目录 零.前言 1.区分贪心算法和动态规划 1.动态规划 2.贪心算法 3.共通点 2.贪心算法得到最优解的条件 1.具有优化子结构 2.具有贪心选择性 3.任务安排问题 1.问题定义 2.优化子结构 3.证明贪心选择性 4.总结 4.哈夫曼编码问题 1.问题定义 2.优化子结构 3.贪心…

一看就懂的贪心算法

如何理解贪心算法 我们先看一个例子 假设有一个可以容纳100kg物品的背包&#xff0c;背包可以装各种物品&#xff0c;我们有以下五种豆子&#xff0c;每种豆子的重量和总价值各不相同。为了让背包中所装物品的总价值最大&#xff0c;我们如何选择在背包中装哪些豆子&#xff…

从零开始学贪心算法

本文在写作过程中参考了大量资料&#xff0c;不能一一列举&#xff0c;还请见谅。 贪心算法的定义&#xff1a; 贪心算法是指在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#xff0c;只做出在某种意义上的局部最优…

如何用wireshark过滤媒体流

进入媒体开发领域的同行来说&#xff0c;一般都会遇到媒体流过滤的问题。那么如何进行媒体流过滤呢&#xff1f; 首先是在媒体服务器的网卡上抓包。其次是获取到通话SIP信令的callid。并根据callid查到sip信令中SDP的IP和PORT。然后用callid及ip和port进行过滤&#xff0c;如果…

WireShark过滤器应用

在工作中我们常会用到wireshark抓取数据包进行分析&#xff0c;当使用wireshark默认设置时&#xff0c;会捕获到大量冗余的数据包&#xff0c;如果没有过滤器过滤&#xff0c;我们很难找到自己想要抓取的数据&#xff0c;这个时候就需要用到wireshark的过滤器来过滤&#xff0c…

Wireshark过滤器写法总结

目录 Wireshark提供了两种过滤器&#xff1a; 1、捕获过滤器 2、显示过滤器 过滤器具体写法 1、显示过滤器写法 1、过滤值比较符号及表达式之间的组合 2、针对ip的过滤 3、针对协议的过滤 4、针对端口的过滤&#xff08;视传输协议而定&#xff09; 5、针对长度和内…

Wireshark 过滤器使用

捕获过滤器&#xff1a; 在抓包之前就设定好过滤条件&#xff0c;然后只抓取符合条件的数据包。 显示过滤器&#xff1a; 在已捕获的数据包集合中设置过滤条件&#xff0c;隐藏不想显示的数据包&#xff0c;只显示符合条件的数据包。 过滤器比较符号 过滤ip和mac地址 ip 改成…

wireshark过滤规则详解

过滤器有两种&#xff1a; 一种是显示过滤器&#xff0c;就是主界面上那个&#xff0c;用来在捕获的记录中找到所需要的记录 一种是捕获过滤器&#xff0c;用来过滤捕获的封包&#xff0c;以免捕获太多的记录。 在Capture -> Capture Filters 中设置 保存过滤&#xff0c…

wireshark 过滤器规则

1、过滤 IP 如来源 IP 或目标 IP。 例子:ip.src eq 192.168.1.107 or ip.dst eq 192.168.1.107 或者ip.addr eq 192.168.1.107 // 都能显示来源 IP 和目标 IP 2、过滤端口 例子: tcp.port eq 80 // 不管端口是来源的还是目标的都显示 tcp.port 80 tcp.port eq 2722 tcp.…

Wireshark过滤器语法

1.官网地址 点击进入 2.捕获过滤器 使用捕获过滤器Wireshark只捕获满足过滤器条件的数据包进来。捕获过滤器采用BPF语法表达式&#xff0c;表达式由如下及部分组成: Dir 指明传输方向是前往还是来自 例如&#xff1a;src、dst Type 指出名字或数字所代表的意&#xff0c;例如…

wireshark过滤telnet

ip.addr172.16.xxx.xxx && tcp.port8080 telnet 端口可以换。可以是23也可以是任意

wireshark过滤器

1、几种条件操作符 eq 等于 ip.addr 192.168.0.1 ip.addr eq 192.168.0.1 ! ne 不等于 !ip.addr192.168.0.1 ip.addr! 192.168.0.1 ip.addr ne 192.168.0.1 > gt 大于 frame.len>64 frame.len gt 64 < lt 小于 frame.le…