• 贪心模板


    区间问题

    区间选点

    给定 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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    最大不相交区间数量

    给定 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;
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    区间分组

    给定 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    优先队列做法。

    #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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    区间覆盖

    给定 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;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    排序不等式

    排队打水

    有 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    绝对值不等式

    货舱选址

    在一条数轴上有 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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    由于找不到vcruntime140_1.dll,无法继续执行代码重新安装程序可能会解决此问题
    智慧校园烟火识别及预警解决方案,保障校园消防安全
    【日志系统】Loki日志监控 - 入门初体验
    boltdb 原理
    android 7.1 mipi 屏 唤醒白屏
    Asymmetric channel bandwidths(非对称信道带宽)
    【Linux系统编程(文件编程)】之创建、打开文件
    Rust-后端服务调试入坑记
    【 OpenGauss源码学习 —— (hash_search)】
    基于改进樽海鞘群算法求解单目标优化问题
  • 原文地址:https://blog.csdn.net/weixin_52465909/article/details/125630088