贪心算法

本文深入讲解了贪心算法的基本思想及应用,通过活动安排、喷水装置覆盖与最优装载问题等实例,展示了如何通过局部最优选择实现全局最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 贪心算法
用途:求最优解一类的问题。

基本思想:
将问题的求解过程看作是一系列选择,每次选择一个输入,每次选择都是当前状态下的最好选择(局部最优解).每作一次选择后,所求问题会简化为一个规模更小的子问题.从而通过每一步的最
优解逐步达到整体的最优解。

常见的问题:活动安排
背包问题,
作业调度,
最短路径,等等。

实践才是检验真理的唯一标准,理论说的再多不如举几个例题详细的分析一下,下面看几个例题。

例题一:活动安排问题
                   
设有n个活动E={1,2,…,n}(n<100)要使用同一资源,同一时间内只允许一个活动使用该资源. 设活动i的起止时间区间[si, fi ) ,如果选择了活动i,则它在时间区间[si, fi )内占用该资源;若区间[si, fi )与[sj, fj )不相交, 则称活动i与j是相容的. 求解目标是在所给的活动集合中选出最大相容活动子集.
设待安排的11个活动起止时间按结束时间的非减序排列



思路:将结束时间排序,找出第一个结束时间最早的活动,然后找出开始时间比第一个结束时间大且结束时间最小的(如上图),以此类推。该思路即为贪心思路。


代码:
#include<cstdio>
#include<algorithm>
using namespace std;
struct Time
{
	int st;
	int endd;//end在有的编辑器中不能作为变量所以用endd代替//
}time[105];
bool cmp(Time a,Time b)
{
	return a.endd <= b.endd;
}
int main()
{
	int n;
	while (scanf ("%d",&n)!=EOF && n)
	{
		for (int i = 1 ; i <= n ; i++)
		{
			scanf ("%d%d",&time[i].st,&time[i].endd);
		}
		sort(time+1,time+1+n,cmp);//将数组按结束时间排序// 
		int ans = 1;//用来记录满足条件的活动个数// 
		int endPos = time[1].endd;//想将第一个活动的结束时间提出// 
		for (int i = 2 ; i <= n ; i++)
		{
			if (time[i].st >= endPos)//直接比较前一个的结束时间与后面的开始时间(注意:此时结束时间已经排好序,不在担心结束时间了)// 
			{
				ans++;
				endPos = time[i].endd;//将第一个结束时间换成第二个满足条件的活动的结束时间// 
			}
		}
		printf ("%d\n",ans);
	}
	return 0;
}

例题二:喷水装置


喷水装置

时间限制:3000 ms  |  内存限制:65535 KB
难度:3
描述
现有一块草坪,长为20米,宽为2米,要在横中心线上放置半径为Ri的喷水装置,每个喷水装置的效果都会让以它为中心的半径为实数Ri(0<Ri<15)的圆被湿润,这有充足的喷水装置i(1<i<600)个,并且一定能把草坪全部湿润,你要做的是:选择尽量少的喷水装置,把整个草坪的全部湿润。
输入
第一行m表示有m组测试数据
每一组测试数据的第一行有一个整数数n,n表示共有n个喷水装置,随后的一行,有n个实数ri,ri表示该喷水装置能覆盖的圆的半径。
输出
输出所用装置的个数
样例输入
2
5
2 3.2 4 4.5 6 
10
1 2 3 1 2 1.2 3 1.1 1 2
样例输出
2
5


简单的话了一个图:




思路:先将喷水装置按照半径从大到小排序,然后一个个放进花园里,每次求出一个喷水装置的范围即为根号下(R^2-1)*2,当喷水装置右边的式子和大于等于20时即可。


下面看贪心算法的代码:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(double a,double b)
{
	return a>b;
}
int main()
{
	int m,n;
	double count=0;//用来记录喷水装置的个数//
	double r[602];
	cin >> m ;//与scanf("%d",&m);一样的效果,cin也是一个输入函数//
	while(m--){
		int j=0;
		cin >> n;//与上面所说的一样//
		for (int i=0;i<n;i++){
			cin >> r[i];//与上面所说的一样// 
		}
		sort(r,r+n,cmp);
		for(j;j<n;j++){
			count+=sqrt(r[j]*r[j]-1)*2;
			if(count>=20)
			{
				break;
			}
		}
		cout << j+1 <<endl;
		count=0; 
		j=0;//将它们两个归零,不影响下一组数据//
	}
	return 0;
}

例题三:最优装载问题


问题描述:
有一批集装箱要装上一艘载重量为c的轮船。其中集装箱i的重量为Wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。 

编程任务: 对于给定的n个集装箱和轮船的载重量C,编程计算装入最多时的集装箱个数。

输入:
输入由多组测试数据组成。每组测试数据输入的第1行中有2个正整数x和y。正整数x是集装箱个数;正整数y是轮船的载重量。接下来的一行中有x个整数,分别表示x个集装箱的重量,它们之间用空格分隔。其中1<=x<=2000,所有正整数不超过231-1
输出:
对应每组输入,输出的每行是计算出的装入最多时的集装箱个数。

样例输入:
4 5
3 5 2 1
样例输出:
2

思路:将装船过程划为多步选择,每步装一个货箱,每次从剩下的货箱中选择重量最轻的货箱.如此下去直到所有货箱均装上船或船上不能再容纳其他任何一个货箱


代码:
#include<stdio.h>
#include<algorithm> 
using namespace std;
bool cmp(int a,int b)
{
	return a<b;
}
int main()
{
	int x,y;
	int count1=0;//用于记录集装箱的个数//
	int count2=0;//用于记录已将装上船的集装箱的重量// 
	int w[2002];//w[1]代表第一个集装箱的重量//
	while (scanf("%d%d",&x,&y)!=EOF)
	{
		for(int i=0;i<x;i++)
		{
			scanf("%d",&w[i]);
		}
		sort(w,w+x,cmp);
		for(int i=0;i<x;i++)
		{
			count2+=w[i];
			
			if(count2>=y)
				break;
			count1++;
		}
		printf("%d\n",count1);
		count1=count2=0;//将两者归零,使之不影响下面一组数据//
	}
	return 0;
}
练习:
南阳理工OJ:
91
12
14
6
杭电OJ:
2037

愿你一生清澈明朗,做你愿做之事,爱你愿爱之人!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值