chapter7-贪心策略-简单贪心
-
问题分解成为多个子问题;
-
子问题求局部最优解;
-
局部最优解组合成原问题的解。
适用范围:如果这类最优化问题具备无后效性,即某个状态以前的过程不会影响以后的状态,而只与当前状态有关,就能保证使用贪心策略一定能够获得全局最优解。
(or换个说法,目前的问题具有最优子结构,全局最优解就由各个子问题的最优解构成的话,就能用贪心策略。)
1简单贪心
FatMouse' Trade-1009OJ
尽可能多的咖啡豆:贪心策略
注意:商品可任意切分,无需买完
问题分析:
胖老鼠-得到最多咖啡豆
//杭电OJ1009-FatMouse' Trade #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 1000; struct room { int JavaBean; int CatFood; }; room r[MAXN]; bool Compare(room a, room b) { //按性价比排序 return (double)a.JavaBean / a.CatFood > (double)b.JavaBean / b.CatFood; } double MaxTrade(int m, int n) { double answer = 0; for(int i = 0; i < n; ++i) { if(m > r[i].CatFood) { answer += r[i].JavaBean; m -= r[i].CatFood; } else { double tmp = (double) m / r[i].CatFood * r[i].JavaBean; answer += tmp; m = 0; break; } } return answer; } int main() { int m, n; while(cin >> m >> n) { if(-1 == m && -1 == n) { break; } for(int i = 0; i < n; ++i) { cin >> r[i].JavaBean >> r[i].CatFood; } sort(r, r + n, Compare); double answer = MaxTrade(m, n); printf("%.3f\n", answer); } }
Senior's Gun-5281OJ
尽可能多的奖金:贪心策略
问题分析:
最强的枪打最弱的怪
//杭电OJ5281-Senior's Gun #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 1e5 + 10; long long gun[MAXN]; long long monster[MAXN]; bool Compare(long long a, long long b) { return a > b; } int MaxMoney(int n, int m) { int answer = 0; for(int i = 0; i < n; ++i) { if(gun[i] <= monster[i] || i >= m) { //枪比怪多 break; } answer += gun[i] - monster[i]; } return answer; } int main() { int t, n, m; cin >> t; for(int i = 0; i < t; ++i) { cin >> n >> m; for(int j = 0; j < n; ++j) { cin >> gun[j]; } for(int k = 0; k < m; ++k) { cin >> monster[k]; } sort(gun, gun + n, Compare); sort(monster, monster + m); //升序 cout << MaxMoney(n, m) << endl; } return 0; }
ECNU 1045. 箱子打包
尽可能少的装箱数:贪心策略
注意条件:每个箱子最多包含两件物品,如果没有这个条件,就变成普通的装箱问题,在多项式时间内无法得到确定的解(NP-hard)。
问题分析:
箱子打包
//箱子打包 2024-03-05 #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 1e5 + 10; int length[MAXN]; int main() { int n, l; cin >> n >> l; for(int i = 0; i < n; ++i) { cin >> length[i]; } sort(length, length + n); int left = 0; int right = n - 1; int answer = 0; while(left <= right) { if(length[left] + length[right] > l) { right--; } else { left++; right--; } answer++; //不管怎样,left = right时一样加一个箱子装这个物品 } cout << answer << endl; }
POJ 2456 Aggressive cows
题目描述:
Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000). His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?
输入:
- Line 1: Two space-separated integers: N and C
- Lines 2..N+1: Line i+1 contains an integer stall location, xi
输出:
- Line 1: One integer: the largest minimum distance
样例输入
5 3
1
2
8
4
9
样例输出
3
问题的诉求:最大的最小间距。注意以后在题目中遇到“最大的最小”、或“最小的最大”这种奇怪的问法,多半都是要通过二分策略来进行解决。
二分策略是贪心策略中的一种,此时问题的求解方法要发生一定变化,从最大值问题转化为一个判定性问题。
冲动的牛
//Aggressive cows 2024-03-07 二分策略 left_most right_most #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 1e5 + 10; int arr[MAXN]; //用于存放牛棚的坐标位置 //n个牛棚,c头牛,最小距离为distance能否做到 bool Judge(int n, int c, int distance) { int current = arr[0]; int number = 1; for(int i = 1; i < n; ++i) { if(arr[i] - current >= distance) { number++; current = arr[i]; } if(number >= c) { return true; } } return false; } int main() { int n, c; while(scanf("%d%d", &n, &c) != EOF) { for(int i = 0; i < n; ++i) { scanf("%d", &arr[i]); } sort(arr, arr + n); //升序 //二分策略 int left = 1; //min_distance = 1 int right = arr[n - 1] - arr[0]; while(left <= right) { int middle = left + (right - left) / 2; if(Judge(n, c, middle)) { left = middle + 1; } else { right = middle - 1; } } printf("%d\n", right); } return 0; }
POJ 3104 Drying
题目描述:
现有n件衣服需要烘干,每件衣服的含水量为ai
如果自然晾干,每分钟含水量减少1
如果使用烘干机烘干,每分钟含水量减少k(直至为0)
只有一台烘干机,每次只能烘干一件衣服,且一次至少使用1分钟
求使所有衣服含水量为0的最少时间是多少
输入:
第一行包含一个数字n(1<= n <= 10^5),表示衣服的数量。第二行有n个数,分别表示各件衣服的含水量ai(1<= ai<= 10^9),第三行一个整数k(1<= ai <= 10^9),表示烘干机一分钟能够减少的含水量。
输出:
输出一个整数,表示烘干衣服所需的最小时间。
样例输入:
3
2 3 9
5
样例输出:
3
题目诉求
最小的烘干时间 : 二分策略
最小值问题 转化为 判定性问题。
代码实现时,判定时间time内能否烘干全部衣服,直接整数相除是有问题的,只会取下整,而实际上我们应该取上整,即使含水量为4,烘干能力为5,也要多花一整分钟的时间。
烘干衣服
//POJ 3104 Drying 2024-03-07 #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int MAXN = 1e5 + 10; int arr[MAXN]; //保存含水量 //n件衣服,在time时间内能否全部烘干 bool Judge(int n, int k, int time) { int hong_time = 0; for(int i = 0; i < n; ++i) { if(arr[i] > time) { int num = ceil((arr[i] - time)*1.0 / (k - 1)); hong_time += num; } if(hong_time > time) { return false; } } return true; } int main() { int n, k; cin >> n; for(int i = 0; i < n; ++i) { cin >> arr[i]; } cin >> k; sort(arr, arr + n); if(k == 1) { cout << arr[n-1] << endl; } //二分策略 int left = 1; //min_need_time = 1 int right = arr[n - 1]; while(left <= right) { int middle = left + (right - left) / 2; if(Judge(n, k, middle)) { right = middle - 1; } else { left = middle + 1; } } cout << left << endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具