ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Acwing 第六章 贪心

2022-01-03 15:35:58  阅读:164  来源: 互联网

标签:Acwing 端点 int 区间 range heap 第六章 include 贪心


一、区间问题

905. 区间选点
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. 最大不相交区间数量
左端点排序做法

#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. 区间分组
给定 N 个闭区间 [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。
输出最小组数。
输入格式
第一行包含整数 N,表示区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示最小组数。
数据范围
1≤N≤105,
−109≤ai≤bi≤109
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

#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;
}

五、时空复杂度分析

一般ACM或者笔试题的时间限制是1秒或2秒。
在这种情况下,C++代码中的操作次数控制在 107∼108107∼108 为最佳。

下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择:

n≤30n≤30, 指数级别, dfs+剪枝,状态压缩dp
n≤100n≤100 => O(n3)O(n3),floyd,dp,高斯消元
n≤1000n≤1000 => O(n2)O(n2),O(n2logn)O(n2logn),dp,二分,朴素版Dijkstra、朴素版Prim、Bellman-Ford
n≤10000n≤10000 => O(n∗n√)O(n∗n),块状链表、分块、莫队
n≤100000n≤100000 => O(nlogn)O(nlogn) => 各种sort,线段树、树状数组、set/map、heap、拓扑排序、dijkstra+heap、prim+heap、Kruskal、spfa、求凸包、求半平面交、二分、CDQ分治、整体二分、后缀数组、树链剖分、动态树
n≤1000000n≤1000000 => O(n)O(n), 以及常数较小的 O(nlogn)O(nlogn) 算法 => 单调队列、 hash、双指针扫描、并查集,kmp、AC自动机,常数比较小的 O(nlogn)O(nlogn) 的做法:sort、树状数组、heap、dijkstra、spfa
n≤10000000n≤10000000 => O(n)O(n),双指针扫描、kmp、AC自动机、线性筛素数
n≤109n≤109 => O(n√)O(n),判断质数
n≤1018n≤1018 => O(logn)O(logn),最大公约数,快速幂,数位DP
n≤101000n≤101000 => O((logn)2)O((logn)2),高精度加减乘除
n≤10100000n≤10100000 => O(logk×loglogk),k表示位数O(logk×loglogk),k表示位数,高精度加减、FFT/NTT

标签:Acwing,端点,int,区间,range,heap,第六章,include,贪心
来源: https://www.cnblogs.com/zjq182/p/15744459.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有