【算法基础课】笔记06——贪心

贪心

数学不等式相关
思路难想,但一般都是考问题转化。证难

区间问题

通用证明思路:
1. a n s > = c n t 2. a n s < = c n t 3. 从 而 a n s = c n t 1.ans>=cnt\\ 2.ans<=cnt\\ 3.从而 ans=cnt 1.ans>=cnt2.ans<=cnt3.ans=cnt

区间选点

原题:https://www.acwing.com/problem/content/907/
908.最大不相交区间数量 同理

  1. 按右端点给区间升序排序
  2. 按顺序枚举区间(有区间含被选过的点则略过,否则选取右端点)
  3. 证明:(反证法找矛盾)

参考代码:

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;
const int N = 100005,INF=-1e9-1;//小心边界的设置
int n,ans=0,l,r,bound=INF;

struct st {
	int l, r;
	bool operator<(const st &W)const {
		return r < W.r;
	}
}st[N];

int main() {
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> st[i].l >> st[i].r;
	}
	sort(st, st + n);

	for(int i=0;i<n;i++)
		if (st[i].l > bound) {
			ans++;
			bound = st[i].r;
		}//记得更新边界

	cout << ans << endl;

	return 0;
}

区间分组

原题:https://www.acwing.com/problem/content/908/

  1. 按左端点升序排序
  2. 枚举(能否放到组中)

l[i]>Max_r
1.存在,放入,更新Max_r
2.不存在,开新组

维护最小值:堆

#include<iostream>
#include<algorithm>
#include<queue>
#include<functional>

using namespace std;
const int N = 100005;
int n;
priority_queue<int, vector<int>, greater<int> >heap;

struct st {
	int l, r;
	bool operator<(const st& W)const {
		return l < W.l;
	}
}st[N];

int main() {
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> st[i].l >> st[i].r;

	sort(st, st + n);
	for (int i = 0; i < n; i++) {
		auto r = st[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() << endl;
	
	return 0;
}

区间覆盖

原题:https://www.acwing.com/problem/content/909/

  1. 左端点升序排序
  2. 枚举区间,在所有能覆盖start的区间中选择右端点最大的区间,更新start为右端点最大值
#include<iostream>
#include<algorithm>
#include<queue>
#include<functional>

using namespace std;
const int N = 100005;
int n,s,t,ans=0;
bool tag = false;
priority_queue<int, vector<int>, greater<int> >heap;

struct st {
	int l, r;
	bool operator<(const st& W)const {
		return l < W.l;
	}
}st[N];

int main() {
	cin >> s >> t;//左右端点
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> st[i].l >> st[i].r;

	sort(st, st + n);
	for (int i = 0; i < n; i++) {
		int j = i, r = -1e9 - 1;//双指针
		while (j < n && st[j].l <= s) {
			r = max(r, st[j].r);
			j++;//在所有能覆盖s的区间中选择右端点最大的点
		}
		if (r < s) {
			ans = -1;
			break;//找不到这样的点,覆盖不了
		}
		ans++;
		if (r >= t) {
			tag = true;//真正找到了
			break;//在右端点的右边,完全可以覆盖
		}
		s = r;//更新起点start为右端点最大值
		i = j - 1;//直接跳过去

	}
	if (!tag)//还是没找到
		ans = -1;

	cout << ans << endl;
	
	return 0;
}

Huffman树

有多少个父节点就被合并多少次——>权值大的放前
每次合并最小的两堆

  1. 权值最小的两点深度最深,互为兄弟
  2. f(n) = f(n-1)+a+b (减而治之,第一步先弄出来)
#include<iostream>
#include<algorithm>
#include<queue>
#include<functional>

using namespace std;
int n,x,ans=0,a,b;
priority_queue<int, vector<int>, greater<int> >heap;

int main() {
    cin >> n;
    while (n--) {
        cin >> x;
        heap.push(x);
    }

    while (heap.size() > 1) {
        a = heap.top();
        heap.pop();
        b = heap.top();
        heap.pop();
        ans += a + b;
        heap.push(a + b);//减而治之
    }

    cout << ans << endl;

    return 0;
}

排序不等式

越往前被等的越久,所以打水时间最长的排后面
——>升序排列
总 时 间 = t 1 ( n − 1 ) + t 2 ( n − 2 ) + . . . 总时间 = t_1(n-1)+t_2(n-2)+... =t1(n1)+t2(n2)+...
该题代码难度不高,记得long long就好

绝对值不等式

分组求和
本质:找中位数
f ( x ) = ∣ x 1 − x ∣ + ∣ x 2 − x ∣ + . . . + ∣ x n − x ∣ f(x) = |x_1-x|+|x_2-x|+...+|x_n-x| f(x)=x1x+x2x+...+xnx

在这里插入图片描述

#include<iostream>
#include<algorithm>

using namespace std;
const int N = 100005;
long long n,ans = 0;
int a[N];

int main() {
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> a[i];
	sort(a, a + n);
	for (long long i = 0; i < n; i++)
		ans += (long long)abs(a[i]-a[n/2]);

	cout << ans << endl;

	return 0;
}

推公式

eg.https://www.acwing.com/problem/content/127/
最优:wi + si从小到大排序

#include<iostream>
#include<algorithm>

using namespace std;

typedef pair<int, int>PII;
const int N = 50005;
long long n,ans = -2e9,sum=0;
PII cow[N];

int main() {
	cin >> n;
	for (int i = 0; i < n; i++) {
		int w, s;
		cin >> w >> s;
		cow[i] = { w + s,w };
	}
	sort(cow, cow + n);
	for (int i = 0; i < n; i++) {
		int w = cow[i].second, s = cow[i].first - w;
		ans = max(ans, sum - s);
		sum += w;
	}

	cout << ans << endl;

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值