赞
踩
贪心算法(英语:greedy algorithm),又称贪婪算法,是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。
—— 维基百科
求最优装载,给出n个物体,第i个物体重量为wi。选择尽量多的物体,使得总重量不超过C。
从小到大
排序,依次选择每个物体,直到装不下为止。这是一种典型的贪心算法,它只顾眼前,但却能得到最优解。有n个物体,第i个物体的重量为wi,价值为vi。在总重量不超过C的情况下让总价值尽量高。每一个物体都可以只取走一部分,价值和重量按比例计算。
价值除以重量的值
最大的,直到重量和正好为C。有n个人,第i个人重量为wi。每艘船的最大载重量均为C,且最多只能乘两个人。用最少的船装载所有人。
在以上的分析中,比j更重的人只能每人坐一艘船。这样,只需用两个下标i和j分别表示当前考虑的最轻的人和最重的人,每次先将j往左移动
,直到i和j可以共坐一艘船,然后将i加1,j减1
,并重复上述操作。
题目描述:
n个人,已知每个人体重。独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人。显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟?
原题链接:51Nod独木舟
代码如下:
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> #include <string> using namespace std; constexpr auto maxn = 10010; // 相当于#define maxn 10010 int n, m, in; vector<int> vec; // 存储人的体重 bool vis[maxn]; // 用于标记上船的人 bool cmp(int a, int b) { return a > b; } int main() { ios::sync_with_stdio(false); cin >> n >> m; // 上船人数和船的承重 for (int i = 0; i < n; i++) { cin >> in; vec.push_back(in); } sort(vec.begin(), vec.end(), cmp); int start = 0, end = vec.size() - 1, ans = 0; while (start < end) { ++ans; int sum = vec[start] + vec[end]; if (sum <= m) { vis[start] = vis[end] = true; start++; end--; } else { vis[start] = true; start++; } } if (start == end && vis[start] == false) { ans++; } cout << ans; return 0; }
数轴上有n个开区间(ai, bi)。选择尽量多个区间,使得这些区间两两没有公共点。
按照bi从小到大的顺序给区间排序
。贪心策略是:一定要选第一个区间。现在区间已经排序成b1≤b2≤b3…了,考虑a1和a2的大小关系:题目描述
X轴上有N条线段,每条线段有1个起点S和终点E。最多能够选出多少条互不重叠的线段。(注:起点或终点重叠,不算重叠)。
原题链接:51Nod不重叠的线段
代码如下:
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; typedef struct { int s, e; }Line; Line L[50005]; bool cmp(Line a, Line b) { return a.e < b.e; } int main() { ios::sync_with_stdio(false); int n; cin >> n; for (int i = 0; i < n; i++) { cin >> L[i].s >> L[i].e; } sort(L, L + n, cmp); int end = L[0].e; int ans = 1; for (int i = 1; i < n; i++) { if (L[i].s >= end) { ans++; end = L[i].e; } } cout << ans; return 0; }
优先队列用法详解(priority_queue)
题目描述
有若干个活动,第i个开始时间和结束时间是[Si,fi),同一个教室安排的活动之间不能交叠,求要安排所有活动,最少需要几个教室?
原题链接:51Nod活动安排问题
代码如下:
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> using namespace std; typedef struct { int s, f; }Line; Line L[50005]; bool cmp(Line a, Line b) { return a.s < b.s; } int main() { ios::sync_with_stdio(false); int n; priority_queue<int, vector<int>, greater<int> > myqueue; cin >> n; for (int i = 0; i < n; i++) { cin >> L[i].s >> L[i].f; } sort(L, L + n, cmp); myqueue.push(L[0].f); int ans = 1; for (int i = 1; i < n; i++) { if (L[i].s < myqueue.top()) { ans++; myqueue.push(L[i].f); } else { myqueue.pop(); myqueue.push(L[i].f); } } cout << ans; return 0; }
数轴上有n个闭区间[ai, bi]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)。
按b从小到大排序
(b相同时a从大到小排序),则如果出现区间包含的情况,小区间一定排在前面。第一个区间应该取哪一个点呢?此处的贪心策略是:取最后一个点,如图8-8所示。数轴上有n个闭区间[ai, bi],选择尽量少的区间覆盖一条指定线段[s,t]。
题目描述
给出N条线段的起点和终点,从中选出2条线段,这两条线段的重叠部分是最长的。输出这个最长的距离。如果没有重叠,输出0。
原题链接:51No线段的重叠
代码如下:
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; typedef struct { int s, e; }Line; Line L[50005]; bool cmp(Line a, Line b) { if (a.s < b.s)return true; if (a.s == b.s && a.e < b.e)return true; return false; } int main() { ios::sync_with_stdio(false); int n; int a, b; int Max = 0; cin >> n; for (int i = 0; i < n; i++) { cin >> L[i].s >> L[i].e; } sort(L, L + n, cmp);// 按起点的大小排序,若起点相同则按终点 for (int i = 0; i < n; i++) { int l = 0; for (int j = i + 1; j < n; j++) { // j代表i的下一个起点 if (L[j].s > L[i].e) break; // 线段无交集 if (L[i].e - L[j].s < Max) break; // 交集小于Max就退出循环 a = min(L[i].e, L[j].e); b = max(L[i].s, L[j].s); l = a - b; if (l > Max) Max = l; } } cout << Max << endl; return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。