ACM算法训练【贪心合集】

简介: ACM算法训练【贪心合集】


1.区间选点(区间问题·贪心)


9a10f8abb9c74eda92f7a3cfbcd8ddd2.png


思路:

①将每个区间按右端点进行排序
②从前往后依次遍历每个区间
③如果当前区间已经被点覆盖,则pass,否则选择区间的最右边的点
④贪心的思想:每次选择局部最优点解,总体达到全部最优解(只有当问题是单峰的情况才可以使用贪心算法)


#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
vector<PII> ports;
bool cmp(PII a,PII b)   //按pair的second排序
{
    return a.second < b.second;
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        ports.push_back({l,r});
    }
    sort(ports.begin(),ports.end(),cmp);
    int ans=0,ed=-2e9;
    for(auto item : ports)
        if(item.first>ed)
        {
            ans++;
            ed=item.second;
        }
    cout<<ans;
    return 0;
}


2.区间分组(区间问题·贪心)


92127b35d5784b60ae9d8e02c98f4aa4.png


思路:

①所有区间按照左端点从小到大排序
②从前往后处理每个区间,对于每个区间,判断能否将其放到某个组中(L[i] <= Max_r)
不存在这样的组,开辟一个新的组;存在这样的组,放在这个组中,并且更新当前组的Max_r


#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
struct Range
{
    int l,r;
}range[N];
bool cmp(Range a,Range b)   //结构体自定义排序
{
    return a.l<b.l;
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        range[i]={l,r};
    }
    sort(range,range+n,cmp);
    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();
    return 0;
}


3.区间覆盖(区间问题·贪心)


89c3ef1591ea4156af6e6558e2cd2d84.png

输入样例:

1 5
3
-1 3
2 4
3 5

输出样例:

2


思路:

①将区间按左端点从小到大排序
②从前往后依次枚举每个区间,在所有能覆盖线段开头start的区间中选择一个右端点最大的
选完后将start更新成右端点的最大值


#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
struct Range
{
    int l,r;
}range[N];
bool cmp(Range a,Range b)
{
    return a.l<b.l;
}
int main()
{
    int st,ed;
    cin>>st>>ed;
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        range[i]={l,r};
    }
    sort(range,range+n,cmp);
    int res=0;
    bool flag=false;
    for(int i=0;i<n;i++)
    {
        int j=i,r=-2e9;
        while(j<n && range[j].l<=st)
        {
            r=max(r,range[j].r);
            j++;
        }
        res++;
        if(r<st) break;
        if(r>=ed)
        {
            flag=true;
            break;
        }
        i=j-1;
        st=r;
    }
    if(flag) cout<<res;
    else cout<<-1;
    return 0;
}


4.耍杂技的牛(权重相加问题·贪心)


d20ff266fa3e40049aa3bc0c3fe2200b.png


数据范围


1≤N≤50000,
1≤Wi≤10,000,
1≤Si≤1,000,000,000


输入样例:


3
10 3
2 5
3 3


输出样例:


2


思路:

按照wi+si从小到大排序排,结果一定是最优解


#include <bits/stdc++.h>
using namespace std;
const int N = 50010;
struct Cow
{
    int w,s,total;
}cow[N];
bool cmp(Cow a,Cow b)
{
    return a.total<b.total;
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int w,s;
        scanf("%d%d",&w,&s);
        cow[i]={w,s,w+s};
    }
    sort(cow,cow+n,cmp);
    int ans=-2e9,sum=0;
    for(int i=0;i<n;i++)
    {
        ans=max(ans,sum-cow[i].s);
        sum+=cow[i].w;
    }
    cout<<ans;
    return 0;
}


5.合并果子(Huffman树)


在一个果园里,达达已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。


达达决定把所有的果子合成一堆。


每一次合并,达达可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。


可以看出,所有的果子经过 n−1 次合并之后,就只剩下一堆了。


达达在合并果子时总共消耗的体力等于每次合并所耗体力之和。


因为还要花大力气把这些果子搬回家,所以达达在合并果子时要尽可能地节省体力。


假定每个果子重量都为 1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使达达耗费的体力最少,并输出这个最小的体力耗费值。


例如有 3 种果子,数目依次为 1,2,9。


可以先将 1、2 堆合并,新堆数目为 3,耗费体力为 3。


接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12,耗费体力为 12。


所以达达总共耗费体力=3+12=15。


可以证明 15 为最小的体力耗费值。


765dffef0eb04a8a951271f929a64504.png


输入样例:


3 
1 2 9


输出样例:


15


每次选权重最小的两堆合并,结果就是全局最优解


#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 a;
        scanf("%d",&a);
        heap.push(a);
    }
    int ans=0;
    while(heap.size()>1)
    {
        int a=heap.top(); heap.pop();
        int b=heap.top(); heap.pop();
        ans+=a; ans+=b;
        heap.push(a+b);
    }
    cout<<ans;
    return 0;
}


6.排队打水(排序不等式)


cd078a8c9b834e429f98ba0d74e80cad.png

输入样例:

7
3 6 1 4 2 5 7

输出样例:

56


排序相加策略:


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


7.货舱选址(绝对值不等式)


634a440f7bb8416cad5210eb9108821f.png


输入样例:


4
6 2 9 1


输出样例:


12


各个货舱的点距离所有货舱的中位数距离最近:


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


目录
相关文章
|
2月前
|
机器学习/深度学习 算法 搜索推荐
搜索推荐DeepFM算法详解:算法原理、代码实现、比赛实战
搜索推荐DeepFM算法详解:算法原理、代码实现、比赛实战
搜索推荐DeepFM算法详解:算法原理、代码实现、比赛实战
|
机器学习/深度学习 算法 数据挖掘
周志华《机器学习》课后习题(第九章):聚类
周志华《机器学习》课后习题(第九章):聚类
1024 0
周志华《机器学习》课后习题(第九章):聚类
|
人工智能 算法
ACM算法训练【双指针算法合集】
思路: 找到i,j的单调性,统一向后移动,使时间复杂度为O(2n) 枚举i,每次看j是否需要向后走,得到最长的长度
80 1
ACM算法训练【双指针算法合集】
|
算法
ACM算法训练【前缀和】
ACM算法训练【前缀和】
43 1
ACM算法训练【前缀和】
|
人工智能 算法
ACM算法训练【区间和·离散化】
1.离散化 离散化:适合条件 (数字的值域非常大,但是个数非常少) 什么是离散化:把值域大的数字的序列映射到从0开始的自然数数组里(无法开辟出值域那么大的数组)
127 1
ACM算法训练【区间和·离散化】
|
算法
ACM算法训练【KMP算法】
ACM算法训练【KMP算法】
71 0
ACM算法训练【KMP算法】
ACM训练题目【股票买卖Ⅱ】
3.思路与代码 贪心思路:看相邻的两天,只要后一天价格比前一天高,那么就无脑进行交易一次,最终得到一个全局的最优解
63 0
ACM训练题目【股票买卖Ⅱ】
|
算法
ACM算法训练【区间合并】
思路: • 按区间左端点排序,每次维护一个区间 • 新增区间的三种关系:
102 0
ACM算法训练【区间合并】
|
算法 C++
ACM算法训练【快速排序】
ACM算法训练【快速排序】
48 0
ACM算法训练【快速排序】