Acwing 第六章 贪心

基础课第六章:贪心(区间问题、哈夫曼树、排序不等式、绝对值不等式、推公式)

一、区间问题

905. 区间选点

image

image

思想:

将每个区间按右端点按小到大排序
从前往后依次枚举每个区间,如果当前区间已经包含选择的点,则直接跳过,否则选择当前区间的右端点

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1e5+10;

struct Range
{
    int l;
    int r;
}range[N];
int n;
int ans = 1;//默认选一个点表示第一个区间
bool cmp(Range a,Range b)
{
    return a.r < b.r;
}

int main()
{
    cin>>n;
    for(int i = 0;i < n;i++)
    {
        cin>>range[i].l>>range[i].r;
    }
    sort(range,range + n,cmp); //将区间按右端点从小到大排序
    int last = range[0].r;
    for(int i = 1;i < n;i++)
    {
        if(range[i].l > last) //由于右端点从小到大排序,若当前区间左端点大于上一区间右端点
        //说明二者无交集,不可能用上一区间的点表示本区间,必须在本区间再找一个点
        {
            ans++;
            last = range[i].r;
        }
    }
    cout<<ans<<endl;
    return 0;
}

908. 最大不相交区间数量

image

左端点排序做法

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
struct Range
{
  int l;
  int r;
}range[N];
int n,a,b;
int ans = 1;
bool cmp(Range a,Range b)
{
    return a.l < b.l;
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a>>b;
        range[i] = {a,b};
    }
    sort(range,range+n,cmp);
    int last = range[n-1].l;
    for(int i = n-2;i>=0;i--)
    {
        if(range[i].r < last)
        {
            ans++;
            last = range[i].l;
        }
    }
    cout<<ans<<endl;
    return 0;
}

906. 区间分组

image

image
O(nlogn)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int N = 1e5+10;
struct Range
{
    int l;
    int r;
}range[N];
int n,a,b;
bool cmp(Range a,Range b)
{
    return a.l < b.l;
}

int main()
{
    cin>>n;
    for(int i = 0;i < n;i++)
    {
        cin>>a>>b;
        range[i] = {a,b};
    }
    sort(range,range + n,cmp);//按左端点从小到大对区间排序
    priority_queue<int,vector<int>,greater<int>>heap; //定义小根堆
    for(int i = 0;i < n;i++)
    {
        if(heap.empty() || range[i].l <= heap.top()) //组数为0 或者 当前区间左端点比最靠左的组右端点小
        //说明不能放进组里,否则会冲突,因此必须新开一个组
        {
            heap.push(range[i].r);
        }
        else //不会发生冲突,可以放进最靠左的组,更新组的最大右端点
        {
            heap.pop();
            heap.push(range[i].r);
        }
    }
    cout<<heap.size()<<endl;//堆中元素个数就是组的数量
    return 0;
}

112

907. 区间覆盖

image

image

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1e5+10;
struct Range
{
    int l;
    int r;
}range[N];

int a,b,n;
int st,ed;//线段的左右端点

bool cmp(Range a,Range b)
{
    return a.l < b.l;
}
int main()
{
    cin>>st>>ed;
    cin>>n;
    for(int i = 0;i < n;i++)
    {
        cin>>a>>b;
        range[i] = {a,b};
    }
    sort(range,range+n,cmp); //将区间按左边界从小到大排序
    int res = 0,r = -2e9;//选择的区间个数,当前选择区间的右边界
    bool state = false;//当前选择的所有区间是否已全部包含线段
    for(int i = 0;i < n;i++)
    {
        int j = i;
        r = -2e9;
        for(j = i;j < n && range[j].l <= st;j++) //找出左端点不大于当前线段且右端点最大的区间
        {
            r = max(r,range[j].r);
        }
        if(r < st) //选定区间右端点比线段的左区间还小,说明根本无法覆盖,直接跳出
        {
            res = -1;
            break;
        }
        res++; //判断有覆盖的可能性后加入当前区间到选择中,选择区间总数加1
        if(r >= ed) //若当前选定区间右端点大于线段右端点,说明成功覆盖
        {
            state = true;
            break;
        }
        st = r;//将start更新成选定区间的右端点
        i = j - 1;//for循环i也要加,故赋值j-1,主要用于优化算法
    }
    if(state == false) res = -1;
    cout<<res<<endl;
    return 0;
}

二、哈夫曼树

数据结构课程中学过了,在此不多赘述
148. 合并果子

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

int n,sum,x;
priority_queue<int,vector<int>,greater<int>>heap;

int main()
{
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cin>>x;
        heap.push(x);
    }
    while(heap.size() > 1)
    {
        int a = heap.top();
        heap.pop();
        int b = heap.top();
        heap.pop();
        sum += a + b;
        heap.push(a + b);
    }
    cout<<sum<<endl;
    return 0;
}

三、排序不等式

913. 排队打水
总时间 = t1 * (n-1) + t2 * (n-2) + …… + tn-1 * 1 + tn * 0
思路
按照从小到大的顺序,总时间最小

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1e5 + 10;
int a[N],n;
long long sum;
int main()
{
    cin>>n;
    for(int i = 1;i <= n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    for(int i = 1;i <= n;i++)
    {
        sum += a[i] * (n-i);
    }
    cout<<sum<<endl;
    return 0;
}

104. 货仓选址
image

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1e5 + 10;
int a[N],n,sum;

int main()
{
    cin>>n;
    for(int i = 0;i<n;i++) cin>>a[i];
    sort(a,a+n);
    for(int i = 0;i < n;i++)
    {
        sum+= abs(a[i] - a[n/2]); //仓库取在中位数上,使得仓库在所有a[1]~a[n],a[2]~a[n-1]距离最小
    }
    cout<<sum<<endl;
    return 0;
}

四、推公式

125. 耍杂技的牛
image
牛的重量和强壮度之和越大,越要放到下面

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 50005;
struct cow
{
    int w;
    int s;
    bool operator<(const cow& t)
    {
        return w+s < t.w + t.s;
    }
}cows[N];

int sum[N];
int n,w,s,danger = -0x3f3f3f3f;
int main()
{
    cin>>n;
    for(int i = 1;i <= n;i++)
    {
        cin>>w>>s;
        cows[i] = {w,s};
    }
    sort(cows+1,cows+n+1);
    for(int i = 1;i <= n;i++)
    {
        sum[i] = sum[i-1] + cows[i].w;
    }
    for(int i = 1;i <= n;i++)
    {
        danger = max(danger,sum[i-1] - cows[i].s);
    }
    cout<<danger<<endl;
    return 0;
}

五、时空复杂度分析

image

posted @   安河桥北i  阅读(34)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示