小鲤算法之贪心入门

本文介绍了贪心算法的基本概念,通过实例演示如何应用贪心策略解决装箱问题和活动选择问题。装箱问题中,通过优先考虑箱子的剩余容量最大化来达到局部最优;活动选择问题中,通过结束时间排序确保活动间的兼容性。通过实例解析,展示了如何在实际编程中实现这两种算法。
摘要由CSDN通过智能技术生成

贪心是什么呢?

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解

废话不多说,我们上题目:

1.装箱问题

假设有N项物品,大小分别为s1​、s2​、…、si​、…、sN​,其中si​为满足1≤si​≤100的整数。要把这些物品装入到容量为100的一批箱子(序号1-N)中。装箱方法是:对每项物品, 顺序扫描箱子,把该物品放入足以能够容下它的第一个箱子中。请写一个程序模拟这种装箱过程,并输出每个物品所在的箱子序号,以及放置全部物品所需的箱子数目。

输入格式:

输入第一行给出物品个数N(≤1000);第二行给出N个正整数si​(1≤si​≤100,表示第i项物品的大小)。

输出格式:

按照输入顺序输出每个物品的大小及其所在的箱子序号,每个物品占1行,最后一行输出所需的箱子数目。

解题思路:

这题的意思是什么呢?从局部来说,就是问一个箱子里最优情况下可以装下几个物品;从整体来说,就是在局部都达到最优情况下,箱子所用的个数。

#include"stdio.h"
#include"stdlib.h"
int main(){
    int n;
    int a[1005]={0},b[1005]={0};            //(1)
    scanf("%d",&n);
    int i,j;
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    for(i=0;i<n;i++){                     //(2)
        for(j=1;j<=n;j++){
            if(b[j]+a[i]<=100){
                b[j]+=a[i];
                printf("%d %d\n",a[i],j);
                break;
            }
        }
    }
    for(i=0,j=0;i<=n;i++){
        if(b[i]){
            j++;
        }
    }
    printf("%d",j);
    return 0;
}

代码解释

(1)创建两个数组,分别存入数据和箱子状态;箱子编号即为数组下标;注意要一一对应;

(2)循环两次,第一重循环对每一个物品遍历,第二重循环看看每个箱子装了什么,直到不能再装;

2.活动选择问题

假定一个有n个活动(activity)的集合S={a1​,a2​,....,an​},这些活动使用同一个资源(例如同一个阶梯教室),而这个资源在某个时刻只能供一个活动使用。每个活动ai​都有一个开始时间si​和一个结束时间fi​,其中0<=si​<fi​<=32767。如果被选中,任务ai​发生在半开时间区间[si​,fi​)期间。如果两个活动ai​和aj​满足[si​,fi​)和[sj​,fj​)不重叠,则称它们是兼容的。也就说,若si​>=fj​或sj​>=fi​,则ai​和aj​是兼容的。在活动选择问题中,我们希望选出一个最大兼容活动集。

输入格式:

第一行一个整数n(n≤1000);

接下来的n行,每行两个整数,第一个si​,第二个是fi​(0<=si​<fi​<=32767)。

输出格式:

输出最多能安排的活动个数。

解题思路:

即怎么让一天安拍最多的活动;怎么做呢?

什么样的活动最先安排?是最先开始的,还是耗时最短的,亦或是最先结束的?

答案是:最先结束的。

那么为什么呢?

我们知道,每个活动完成后贡献是一样的。那么理想状态是一个活动结束后另一个活动马上开始,然后接着下去······直到所用活动结束。但是现实怎么可能呢?不过类似的,我们按照结束时间排序,只要满足前一个结束时间大于后一个开始时间,那么它就是我们的局部最优解了~~~

下面是代码:

#include<stdio.h>
struct {
 int a;int b;
}typedef s;                                 //(1)
int main()
{   int n,cot=0;
    int i,j,t=0;
    s m[1000];
	s tem;
    scanf("%d",&n);
    for(i=0;i<n;i++){
    scanf("%d%d",&m[i].a,&m[i].b);
    }
	for( i=0;i<n-1;i++)
	{
		for(j=0;j<n-1-i;j++)              //(2)
		{
			if(m[j].b>m[j+1].b)
			{
				tem =m[j+1];
				m[j+1]=m[j];
				m[j]=tem;
 
			}
		}
	}
	t=m[0].b;
	cot=1;                               //(3)
	for(i=1;i<n;i++){
		if(t<=m[i].a){
			t=m[i].b;
			cot++;}
	}
    
    printf("%d",cot);
    return 0;
}

代码解释

(1)创建一个结构体struct s,它有两个成员,一个是开始时间,一个是结束时间;至于为什么要用结构体,当然是方便啦。结束时间排序时,开始时间也要跟着动,不然不是乱了吗?

(2)冒泡实现结束时间排序;

(3)排序之后遍历,如果满足我们在解题思路里说的条件,欧克,它就是那个幸运儿,被选上了。

今天的内容已经结束了>_<

如果我的文章对你有帮助,不要吝惜你的点赞,小鲤希望得到你的支持ლ(´ڡ`ლ)

求三连和关注!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值