算法基础课之贪心算法

算法基础课之贪心算法

1. 区间选点

在这里插入图片描述

题解:

算法思想:

  1. 现将所有区间存在定义的结构体数组中
  2. 按照最右端点从小到排序
  3. 再设置一个最小点 ed=-2e9
  4. 当最小点ed不在区间里时,ed变为该区间的右端点,计数res+1

算法复杂度为(nlongn)

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
struct Range
{
    int l,r;
    bool operator< (const Range &W)const
    {
        return r<W.r;
    }
}range[N]; //用于存放n个区间
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>range[i].l>>range[i].r;
    }
    sort(range,range+n);
    int res=0,ed=-2e9;
    for(int i=0;i<n;i++)
    {
        if(ed<range[i].l)
        {
            ed=range[i].r;
            res++;
        }
    }
    cout<<res<<endl;
    return 0;
}

2. 最大不相交数量

在这里插入图片描述

题解:

最大区间不相交数量这一题类似于
小明在一天中有n个活动可供参加,每个活动都有开始时间和结束时间,请据此选择小明最多可参加的活动数量
算法思想和区间选点相同

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
struct Range
{
    int l,r;
    bool operator< (const Range &W)const
    {
        return r<W.r;
    }
}range[N]; //用于存放n个区间
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>range[i].l>>range[i].r;
    }
    sort(range,range+n);
    int res=0,ed=-2e9;
    for(int i=0;i<n;i++)
    {
        if(ed<range[i].l)
        {
            ed=range[i].r;
            res++;
        }
    }
    cout<<res<<endl;
    return 0;
}

3. 区间分组

在这里插入图片描述

题解:

STL中的堆的定义方法是
priority_queue[HTML_REMOVED]> 默认为大根堆
若要变为小根堆要在后面加上greater[HTML_REMOVED]
小根堆栈顶元素top()为栈中最小值

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
struct Range
{
    int l,r;
    bool operator< (const Range &W)const
    {
        return l<W.l;
    }
}range[N];
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>range[i].l>>range[i].r;
        
    }
    sort(range,range+n);
    priority_queue<int,vector<int>,greater<int>>heap;
    for(int i=0;i<n;i++)
    {
        if(heap.empty()||heap.top()>=range[i].l)
        {
            heap.push(range[i].r);
        }
        else{
            heap.pop();
            heap.push(range[i].r);
        }
    }
    cout<<heap.size()<<endl;
    return 0;
    
}

4. 区间覆盖

在这里插入图片描述

题解:

算法思想:

  1. 把所有区间按左端点从小到大排序
  2. 找出l<=st的所有区间的右端点的最大值r(用双指针算法)
  3. 将r赋值给st,直到r>=ed
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
struct Range{
    int l,r;
    bool operator< (const Range &W)const
    {
        return l<W.l;
    }
}range[N]; 

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int st,ed;
    cin>>st>>ed;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>range[i].l>>range[i].r;
    }
    sort(range,range+n);
    int res=0; //用来记录最少区间数 
    bool flag=false;
    for(int i=0;i<n;i++)
    {
        //双指针算法,找出所有l<=st的区间中,r最大的
        int j=i,r=-2e9;
        while(j<n&&range[j].l<=st)
        {
            r=max(r,range[j].r);
            j++;
         } 
        // 情况1:再所有满足l<=st的区间中,最大的r还是小于st
        // 这种情况,不用再将r赋值给st了,直接跳出循环
        if(r<st)
        {
            flag=true;
            break;
         }
         res++;
        // 情况2:r>=ed,直接第一次就找到了全覆盖的区间,也跳出循环
        if(r>=ed) 
        {
            break;
        }

        st=r;
        i=j-1;
        if(j==n)
        {
            flag=true;
            break;
        }



    }
    if(flag) cout<<-1<<endl;
    else cout<<res<<endl; 
    return 0;
}

5. 合并果子

在这里插入图片描述

题解:

算法思想,其实这题类似于石子合并问题
利用哈夫曼数,合并最小两数的思想,将所有数放在小根堆中,堆顶元素top为最小值,当堆中元素大于1时,两个最小元素相加,然后计算和,出堆,和入堆

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin>>n;
    priority_queue<int,vector<int>,greater<int>>heap;
    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        heap.push(x);
    }
    int res=0;
    while(heap.size()>1)
    {
        int a = heap.top(); heap.pop();
        int b = heap.top();heap.pop();
        res+=(a+b);
        heap.push(a+b);
    }
    cout<<res<<endl;
    return 0;

}

6. 排队打水

在这里插入图片描述

题解:

等待时间最小的放在前面,先打水

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100010;
int a[N];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    sort(a,a+n);
    LL res=0;
    for(int i=0;i<n;i++)
    {
        res+=(a[i]*(n-i-1));
    }
    cout<<res<<endl;
    return 0;
}

7. 仓货选址

在这里插入图片描述

题解:

算法思想:
排完序只有找中位数,放在中位数上里各个点的距离最小

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N];
int n;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    sort(a,a+n);
    int res=0;
    for(int i=0;i<n;i++)
    {
        res+=(abs(a[i]-a[n/2]));
    }
    cout<<res<<endl;
    return 0;

}

8. 耍杂技的牛

在这里插入图片描述

题解:

算法思想:
根据w+s的和排序,最小的牛站在最上面

#include<bits/stdc++.h>
using namespace std;
const int N = 50010;
typedef long long LL;
typedef pair<int, int> PII;
PII a[N];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int w,s;
        cin>>w>>s;
        a[i].first=(w+s);
        a[i].second=s;
    }
    sort(a,a+n);
    LL sum=0,res=-2e18;
    for(int i=0;i<n;i++)
    {
        sum-=a[i].second;
        res=max(res,sum);
        sum+=a[i].first;
    }
    cout<<res<<endl;
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值