贪心算法一句话总结:只在当前状态选择最优解,从而达到整体的最优解。
第一类:背包相关问题
- 最优装载问题
- 部分背包问题
- 乘船问题
第二类:区间相关问题
- 选择不相交区间
- 区间选点问题
- 区间覆盖问题
第一类:背包相关问题
最优装载问题:给出n个物体,第i个物体重量为w(i)。选择尽量多的物体,使得总重量不超过C。
贪心策略:把物体从小到大选,知道装不下为止。
部分背包问题:有n个物体,第i个的重量为w(i),价值为v(i)。在总重量不超过C的情况下让总价值最高。每一个物体都可以只取走一部分,价值和重量按比例计算。
贪心策略:优先拿 v/w 最大的,直到重量正好为C。
P2240 【深基12.例1】部分背包问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
乘船问题:有n个人,第i个人重量为w(i)。每艘船的最大载重量均为C,且中最多只能乘两个人。要求用最少的船装载所有人。
贪心策略:先考虑当前最轻的人i,应该和能够与他一起坐船中的人中最重的人一起坐船,否则i一人坐一船。
P1094 [NOIP2007 普及组] 纪念品分组 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
第二类:区间相关问题
选择不相交区间:数轴上有n个开区间(ai,bi)。选择尽量多个区间,使这些区间没有公共点。
贪心策略:将bi从小到大排序,选择排序后的第一个区间,知道选完或不能选为止。
P1803 凌乱的yyy / 线段覆盖 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
区间选点问题:数轴上有n个闭区间[ai,bi]。取尽量少的点,使得每个区间都至少有一个点。
贪心策略:将bi从小到大排序,取第一个区间的最后一个点。
区间覆盖问题:数轴上有n个闭区间[ai,bi],选择尽量少的区间覆盖一条指定线段[s,t],ai<s。
贪心策略:将ai从小到大排序,选择排序后的覆盖[s,t]最长的区间。
贴两个贪心题的代码实现:
P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <iostream>
#include <algorithm>
using namespace std;
int a[10005] = {0}, n, s = 0;
int main(void) {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n - 1; i++) {
s += a[i] + a[i + 1];
a[i + 1] += a[i];
for (int j = i + 1; j <= n - 1; j++)
if (a[j] > a[j + 1])
swap(a[j], a[j + 1]);
else break;
}
cout << s;
return 0;
}
P1106 删数问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
char N[300] = {'0'};
int k, cnt = 0;
int main(void) {
fill(N, N + 300, '0');
scanf("%s %d", &N[1], &k);
int len = strlen(N) - 1;
while (cnt != k) {
for (int i = 1; i <= len; i++) {
if (N[i] == 'x')
continue;
int p = i + 1;
while (N[p] == 'x')
p++;
char R = N[p];
if (N[i] > R) {
N[i] = 'x';
cnt++;
break;
}
}
}
int st = 1;
for (int i = 1; i <= len; i++) {
if (len - k == 1)
st = 0;
if (st && N[i] == '0')
continue;
if (N[i] != 'x') {
printf("%c", N[i]);
st = 0;
}
}
return 0;
}