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

本文介绍了贪心算法的概念,包括其在最优子结构和贪心选择性质下的应用,如最小生成树、哈夫曼编码、活动选择等问题。解题步骤包括理解问题、贪心选择、分解子问题等,并给出了两个实际问题的示例:计算二进制相同1数目的最小数和奶牛塔问题。提醒读者注意贪心算法并不一定得到全局最优解,需谨慎使用。
摘要由CSDN通过智能技术生成

一、概念(是什么)

       贪心算法(Greedy Algorithm)是一种在解决问题时,每一步都采取在当前看来是最好的选择,希望通过局部最优的选择,达到全局最优的算法策略。

二、适合的题型(为什么)

           贪心算法适合解决那些具有最优子结构和贪心选择性质的问题。最优子结构意味着问题的最优解包含其子问题的最优解,而贪心选择性质意味着在每一步选择中,都能做出在当前看来最优的选择。以下是一些适合使用贪心算法解决的问题:
 1.最小生成树:例如,克鲁斯卡尔算法(Kruskal’s algorithm)和普里姆算法(Prim’s algorithm)都是使用贪心策略来构建最小生成树的。
哈夫曼编码:哈夫曼算法通过贪心选择频率最小的字符来构建哈夫曼树,从而实现字符的最优编码。
 2.活动选择问题:在给定的活动中选择最多数的活动,使得这些活动的总时间不超过一天的时间限制。
 3.背包问题:特别是在0-1背包问题中,贪心算法可以用来寻找一个近似最优解。
最长公共子序列(LCS):虽然LCS问题本身不适合使用贪心算法,但是贪心算法可以用来找到LCS的一个最长子序列。
 4.股票买卖问题:在给定的n天中,找到最大利润的买卖组合。
最小路径和:在加权图中找到从源点到目的地的路径,使得路径上权值之和最小。
元素覆盖问题:例如,最小数组覆盖问题,要求选择最少的数组元素,使得这些元素的和覆盖所有其他元素的和。
贪心算法在处理这些问题时,通常能够提供多项式时间复杂度的解决方案,这在很多情况下是非常有吸引力的。然而,贪心算法不总是能得到全局最优解,因此在使用贪心算法之前,需要对问题进行适当的分析,确保它满足最优子结构和贪心选择性质。如果不满足这些条件,可能需要考虑其他算法策略

三、解题步骤(怎么做)

使用贪心算法解题通常需要以下几个步骤:
1.理解问题:首先要充分理解问题的性质,确定问题的目标是什么,以及如何衡量解的好坏。
2.贪心选择:根据问题的性质,找到一个局部最优解的选取策略,这个策略应该能够使得问题的子结构最优。也就是说,在这个步骤中,你需要确定在每一步决策中,如何做出选择以达到局部最优。
3.问题的分解:将原问题分解为若干个子问题,每个子问题都是原问题的一个局部情况。
贪心算法实现:根据贪心选择策略,对每个子问题采用局部最优解。
4.子问题的合并:将每个子问题的解合并起来,得到原问题的一个解。
5.结果验证:最后需要验证通过贪心算法得到的解是否是全局最优解。由于贪心算法只考虑局部最优解,所以并不保证得到的是全局最优解,这一步是非常重要的。

四、例题

题目描述

xx老师是业内大牛,许多学生都想跟xx老师学习,其中也包括dd。老师知道dd在学编程,就对dd说,如果你能做出下面这题,并且你能很好的学会动态规划、搜索、图论等内容,就收dd为徒。

为了能投到老师门下,DD开始认真思考这问题:

给定一个正整数N,求最小的、比N大的正整数M,使得M与N的二进制表示中有相同数目的1。

举个例子,假如给定的N为78,其二进制表示为1001110,包含4个1,那么最小的比N大的并且二进制表示中只包含4个1的数是83,其二进制是1010011,因此83就是答案。

输入格式

输入若干行,每行一个数n(1≤n≤1000000),输入"0"结束。

输出格式

输出若干行对应的值。

输入样例 

1 2 3 4 78 0

输出样例 

2 4 5 8 83

 

#include <iostream>
#include <bitset>

int countOnes(int n) {
    int count = 0;
    while (n) {
        count += n & 1;
        n >>= 1;
    }
    return count;
}

int findNextNumber(int n) {
    int ones = countOnes(n);
    do {
        n++;
    } while (countOnes(n) != ones);
    return n;
}

int main() {
    int n;
    while (std::cin >> n && n != 0) {
        std::cout << findNextNumber(n) << std::endl;
    }
    return 0;
}

题目描述

    Farmer  John最近为奶牛们的图书馆添置了一个巨大的书架,尽管它是如此 的大,但它还是几乎瞬间就被各种各样的书塞满了。现在,只有书架的顶上还留 有一点空间。         
所有头奶牛都有一个确定的身高。设所有奶牛身高的和为S,书架的高度为B。         
      为了够到比最高的那头奶牛还要高的书架顶,奶牛们不得不象演杂技一般, 一头站在另一头的背上,叠成一座“奶牛塔”。当然,这个塔的高度,就是塔中 所有奶牛的身高之和。
为了往书架顶上放东西,所有奶牛的身高和必须不小于书 架的高度。显然,塔中的奶牛数目越多,整座塔就越不稳定,于是奶牛们希望在 能够到书架顶的前提下,让塔中奶牛的数目尽量少。         
现在,奶牛们找到了你,希望你帮她们计算这个最小的数目。

输入格式

*  第1行:  2个用空格隔开的整数:N  和  B *  第2..N+1行:  第i+1行是1个整数:H_i
N(1  < =  N  < =  20,000)
H_i (1  < =  H_i  < =  10,000)
并且保证 1  < =  B  < =  S  <   2,000,000,007

输出格式

*  第1行:  输出1个整数,即最少要多少头奶牛叠成塔,才能够到书架顶部

输入样例 

解释

6 40 6 18 11 13 19 11

输出样例 
3
数据范围与提示

输入说明:         一共有6头奶牛,书架的高度为40,奶牛们的身高在6..19之间。 输出说明:         一种只用3头奶牛就达到高度40的方法:18+11+13。当然还有其他方法,在 此不一一列出了。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int N, B;
    cin >> N >> B;

    vector<int> heights(N);
    for (int i = 0; i < N; i++) {
        cin >> heights[i];
    }

    sort(heights.begin(), heights.end(), greater<int>());

    int sum = 0;
    int count = 0;
    for (int i = 0; i < N; i++) {
        sum += heights[i];
        count++;
        if (sum >= B) {
            break;
        }
    }

    cout << count << endl;

    return 0;
}

题目描述

假设山洞里有n种宝物,每种宝物有一定重量w和相应的价值v,毛驴运载能力有限,只能运走m重量的宝的宝物,一种宝物只能拿一样,宝物可以分割。那么怎么才能使毛驴运走宝物的价值最大呢?

#include<bits/stdc++.h>
using namespace std;

struct bao_wu{
	double a;
	double b;
	double c;
}s[10001]; 
bool cmp(bao_wu a,bao_wu b){
	return a.c>b.c;
}
int main(){
	int n;
	double k;
	double sum=0;
	cin>>n>>k;
	for(int i=0;i<n;i++){
		cin>>s[i].a>>s[i].b;
		s[i].c=s[i].b/s[i].a;
	}
	sort(s,s+n,cmp);
	for(int i=0;i<n;i++){
		if(s[i].a<k){
			k=k-s[i].a;
			sum+=s[i].b;
		}
		else{
			sum+=k*s[i].c;
			break;
		}
	}
	printf("%.1lf",sum);
	return 0;
}

  • 19
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值