区间问题
区间选点
给定 N 个闭区间 [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。
输出选择的点的最小数量。
位于区间端点上的点也算作区间内。
输入格式
第一行包含整数 N,表示区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需的点的最小数量。
数据范围
1≤N≤1e5,
−1e9≤ai≤bi≤1e9
先对右端点进行排序,有交集的区间进行右端点的更新,没有交集则点数+1。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node{
int a,b;
bool operator<(const node&w)const {
return b<w.b;}
}range[N];
int main(){
int n;
cin>>n;
int a,b;
for(int i=0;i<n;i++){
cin>>a>>b;
range[i]={a,b};
}
sort(range, range+n);
int s=-2e9,cnt=0;
for(int i=0;i<n;i++){
if(s<range[i].a){
cnt++;
s=range[i].b;
}
}
cout<<cnt;
return 0;
}
最大不相交区间数量
给定 N 个闭区间 [ai,bi],请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。
输出可选取区间的最大数量。
输入格式
第一行包含整数 N,表示区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示可选取区间的最大数量。
数据范围
1≤N≤1e5,
−1e9≤ai≤bi≤1e9
先对右端点进行排序,有交集的区间进行右端点的更新,没有交集则点数+1。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node{
int a,b;
bool operator<(const node&w)const{
return b<w.b;
}
}range[N];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n;
cin>>n;
for(int i=0;i<n;i++){
int a,b;
cin>>a>>b;
range[i]={a,b};
}
int res=0,s=-2e9;
sort(range,range+n);
for(int i=0;i<n;i++){
if(range[i].a>s){
s=range[i].b;
res++;
}
}
cout<<res;
return 0;
}
区间分组
给定 N 个闭区间 [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。
输出最小组数。
输入格式
第一行包含整数 N,表示区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示最小组数。
数据范围
1≤N≤1e5,
−1e9≤ai≤bi≤1e9
先区分左右端点进行排序,再遍历取左右 端点未抵消的最大值。
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
int b[2 * N], idx;
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
int l, r;
cin >> l >> r;
b[idx++] = l * 2;
b[idx++] = r * 2 + 1;//用奇偶性区分左右端点
}
sort(b, b + idx);
int res = 1, t = 0;
for (int i = 0; i < idx; i++) {
if (b[i] % 2 == 0)t++;
else t--;
res = max(res, t);
}
cout << res;
return 0;
}
优先队列做法。
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
struct Range {
int l, r;
bool operator <(const Range& w)const {
return l < w.l;
}
}range[N];
int n;
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
int l, r;
cin >> l >> r;
range[i] = { l,r };}
sort(range, range + n);
int res = 0,ed=-2e9;
priority_queue<int, vector<int>, greater<int>>heap;
for (int i = 0; i < n; i++) {
auto r = range[i];
if (heap.empty() || heap.top() >= r.l)heap.push(r.r);
else {
int t = heap.top();
heap.pop();
heap.push(r.r);
}
}
cout << heap.size();
return 0;
}
区间覆盖
给定 N 个闭区间 [ai,bi] 以及一个线段区间 [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。
输出最少区间数,如果无法完全覆盖则输出 −1。
输入格式
第一行包含两个整数 s 和 t,表示给定线段区间的两个端点。
第二行包含整数 N,表示给定区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需最少区间数。
如果无解,则输出 −1。
数据范围
1≤N≤1e5,
−1e9≤ai≤bi≤1e9,
−1e9≤s≤t≤1e9
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
struct Range {
int l, r;
bool operator <(const Range& w)const {
return l < w.l;
}
}range[N];
int main() {
int n;
int st, ed;
cin >> st >> ed;
cin >> n;
for (int i = 0; i < n; i++) {
int l, r;
cin >> l >> r;
range[i] = { l,r };
}
sort(range, range + n);
int res = 0;
bool sc = 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++;
}
if (r < st) {
res = -1;
break;
}
res++;
if (r >= ed) {
sc = true;
break;
}
i = j-1;
st = r;
}
if (!sc)cout << -1;
else cout << res;
return 0;
}
Huffman树
合并果子
在一个果园里,达达已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。
达达决定把所有的果子合成一堆。
每一次合并,达达可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。
可以看出,所有的果子经过 n−1 次合并之后,就只剩下一堆了。
达达在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以达达在合并果子时要尽可能地节省体力。
假定每个果子重量都为 1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使达达耗费的体力最少,并输出这个最小的体力耗费值。
例如有 3 种果子,数目依次为 1,2,9。
可以先将 1、2 堆合并,新堆数目为 3,耗费体力为 3。
接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12,耗费体力为 12。
所以达达总共耗费体力=3+12=15。
可以证明 15 为最小的体力耗费值。
输入格式
输入包括两行,第一行是一个整数 n,表示果子的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 ai 是第 i 种果子的数目。
输出格式
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。
输入数据保证这个值小于 231。
数据范围
1≤n≤10000,
1≤ai≤20000
只需要用优先队列先取出两个,再插入一个,直至最后剩下一个。
#include<iostream>
#include<algorithm>
#include<queue>
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin>>n;
priority_queue<int, vector<int>, greater<int>>heap;
while (n--) {
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();
int c = a + b;
heap.push(c);
res += c;
}
cout << res;
return 0;
}
排序不等式
排队打水
有 n 个人排队到 1 个水龙头处打水,第 i 个人装满水桶所需的时间是 ti,请问如何安排他们的打水顺序才能使所有人的等待时间之和最小?
输入格式
第一行包含整数 n。
第二行包含 n 个整数,其中第 i 个整数表示第 i 个人装满水桶所花费的时间 ti。
输出格式
输出一个整数,表示最小的等待时间之和。
数据范围
1≤n≤1e5,
1≤ti≤1e4
值正序,下标倒序相乘得到最小值
#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++) {
cin >> a[i];
}
sort(a, a + n);
int x=n;
long long res=0;
for (int i = 0; i < n; i++) {
res += a[i] * (x - 1);
x--;
}
cout << res;
return 0;
}
绝对值不等式
货舱选址
在一条数轴上有 N 家商店,它们的坐标分别为 A1∼AN。
现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。
为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。
输入格式
第一行输入整数 N。
第二行 N 个整数 A1∼AN。
输出格式
输出一个整数,表示距离之和的最小值。
数据范围
1≤N≤100000,
0≤Ai≤40000
只需统计各点到中位数的距离之和。
#include <bits/stdc++.h>
using namespace std;
const int N=100100;
int a[N],n,i,ans,sum;
int main()
{
cin>>n;
for (i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);//排序
int sm=a[n/2+1];//中位数
for (i=1;i<=n;i++)
ans=ans+abs(a[i]-sm);//统计和中位数之间的差
cout<<ans;
return 0;
}
以上就是C++实现贪心算法的示例详解的详细内容,更多关于C++ 贪心算法的资料请关注编程网其它相关文章!