【蓝桥杯算法笔记】贪心

K.贪心

基础知识

1.含义:

①很贪婪:找最优解

②很短视:只会看重眼前的局面不会往后想

2.题目特点:

①跳跃性很强:没有固定的模型,所有贪心题基本上没有什么共性

②可能代码很短,但结论证明很难

3.解题策略:

①找相似

考试的时候看一下这道题跟平时做的有没有相似的,然后套一下相似题目的做法

所以平时多积累归纳总结不同的贪心模型

②猜

考试实在不会就只能猜了,一般贪心题的虽然策略证明很麻烦,但代码都很短,一般可能就是按照按照某个关键字排个序,然后从小到大处理一遍就可以了。

4.一些话:

①贪心题一般都是先猜然后再去证明正确性

②很多贪心问题都可以转换成数学模型,是因为出题人根据数学模型加了些背景出了这些贪心题

例题

一、股票买卖II

1.策略:

(策略就是做法)

遇增则买:依次看相邻两天,只要后一天价格大于前一天的价格,则交易一次,加起他们之间的差值

2.证明:

性质:任何跨度大于一天的交易都可以拆分成若干个跨度等于一天的交易

所以可以独立的看只要每一段上升的全部都加起来

在这里插入图片描述

3.代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n;
int price[N];

int main()
{
   
   
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d", &price[i]); //输入比较长,推荐使用scanf

    int res = 0;
    for (int i = 0; i + 1 < n; i ++ ) //依次遍历所有跨度为1的交易
    {
   
   
        int dt = price[i + 1] - price[i];  //算交易
        if (dt > 0)//只要交易是正的,统计加起来
            res += dt;
    }

    printf("%d\n", res);

    return 0;
}
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int a[100010];  //注意题目数据范围
int n;
int main()
{
    cin>>n;
    
    for(int i=1;i<=n;i++) cin>>a[i];
    
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]<a[i+1])
            sum+=(a[i+1]-a[i]);
    }
    cout<<sum;
    return 0;
}
4.总结:

一开始思路:可以从数学坐标轴去理解找到这道题解法,在折线图中,可以发现交易时一定是上升的折线,所以只需要找到拐点,即该点小于两边的点和该点大于两端的点,然后求和算出每段上升折线这两段一小一大两个点的差值即可。代码实现时还要注意特判一下整个两端的边界,分多种情况讨论。

后来发现上述的性质,其实每一段上升的折线都可以分成若干个相邻天数之间的上升端,所以就简单了,直接找比前一个大的小段即可。

在这里插入图片描述

二、货仓选址

1.策略:

排序+中位数

①奇数个商店:在中位数

②偶数个商店:中间两个数之间都可

注意:这两个可以合并,偶数个商店时,在中间两个数之间任意点都可,包括这两个点。不管奇数个商店,还是偶数个商店,直接选取中间靠右端点就包括这两种情况。(如果选用中间靠左端点,奇数个时还需单独讨论)。又因为C++中的/是向下取整,所以

当下标从0开始时,mid=a[n/2]

当下标从1开始时,mid=a[n/2+1]

2.证明:

可以发现这个问题可以用数学公式表示,然后利用分组通过几何意义来求解这个公式
在这里插入图片描述

(很多贪心问题都可以转换成数学模型,是因为出题人根据数学模型加了些背景出了这些贪心题)

3.代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010;

int n;
int x[N]; //用x表示坐标

int main()
{
   
   
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d", &x[i]); //输入所有的坐标
    sort(x, x + n);//依次给所有的坐标排序

    int c = x[n / 2]; //求出商店的位置在中点,c++中的/是向下取整
    LL res = 0;  //注意会不会爆int,用longlong存保险
    for (int i = 0; i < n; i ++ ) res += abs(x[i] - c); //求一下到中点的距离

    printf("%lld\n", res);

    return 0;
}
//奇数偶数个时分开看
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=100010;
int a[N];
int n;
int main()
{
   
   
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);

    int mid;
    if(n%2!=0)
    mid=a[n/2+1];
    else
    mid=a[n/2];

    int sum=0;
    for(int i=1;i<=n;i++)
    {
   
   
        sum+=a
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值