Acwing 第六章 贪心
基础课第六章:贪心(区间问题、哈夫曼树、排序不等式、绝对值不等式、推公式)
一、区间问题
905. 区间选点
思想:
将每个区间按右端点按小到大排序
从前往后依次枚举每个区间,如果当前区间已经包含选择的点,则直接跳过,否则选择当前区间的右端点
#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. 区间分组
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. 区间覆盖
#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;
}
#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. 耍杂技的牛
牛的重量和强壮度之和越大,越要放到下面
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于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)