贪心算法的难点:贪心的证明
区间问题
例:最大不相交区间问题:给定一组区间,选择尽可能多的不相交区间。
已知通过贪心算法得到的区间数量为cnt
,最大区间数量为ans
,因此ans >= cnt
;又因为不使用贪心算法的话,每选择一个区间后,为后续区间留下的长度l1
较贪心算法相应步骤时留下的长度l2
更短,因此ans <= cnt
,故证明ans == cnt
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
| struct Interval { int start, end; };
bool compareIntervals(const Interval& a, const Interval& b) { return a.end < b.end; }
vector<int> minPoints(vector<Interval>& intervals) { if (intervals.empty()) return {};
sort(intervals.begin(), intervals.end(), compareIntervals);
vector<int> points; int lastPoint = intervals[0].end; points.push_back(lastPoint);
for (const auto& interval : intervals) { if (interval.start > lastPoint) { lastPoint = interval.end; points.push_back(lastPoint); } }
return points; }
|
哈夫曼树
哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树,它的性质:
构建哈夫曼树的过程:
- 将所有字符及其频率作为叶子节点,放入一个最小堆(优先队列)。
- 每次从堆中取出两个频率最小的节点,合并成一个新节点,新节点的频率为这两个节点的频率之和。
- 将新节点重新插入堆中。
- 重复上述过程,直到堆中只剩一个节点,这个节点就是哈夫曼树的根节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| HuffmanNode* buildHuffmanTree(const vector<char>& data, const vector<int>& freq) { priority_queue<HuffmanNode*, vector<HuffmanNode*>, Compare> minHeap;
for (size_t i = 0; i < data.size(); ++i) { minHeap.push(new HuffmanNode(data[i], freq[i])); }
while (minHeap.size() > 1) { HuffmanNode* left = minHeap.top(); minHeap.pop(); HuffmanNode* right = minHeap.top(); minHeap.pop();
HuffmanNode* newNode = new HuffmanNode('$', left->freq + right->freq); newNode->left = left; newNode->right = right;
minHeap.push(newNode); }
return minHeap.top(); }
|
绝对不等式
$$
|a-x| + |b-x| \geq |a-b|
$$
问题描述:在一条数轴上有 n个商店,每个商店的位置为$x_i$,现在需要选择一个位置建立货仓,使得货仓到所有商店的距离之和最小。
。现在需要选择一个位置建立货仓,使得货仓到所有商店的距离之和最小。
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
| #include <iostream> #include <vector> #include <algorithm> using namespace std;
int main() { int n; cin >> n; vector<int> x(n); for (int i = 0; i < n; i++) { cin >> x[i]; }
sort(x.begin(), x.end());
int warehouse = x[n / 2];
long long total_distance = 0; for (int i = 0; i < n; i++) { total_distance += abs(x[i] - warehouse); }
cout << total_distance << endl; return 0; }
|
推公式
有 n 头牛叠罗汉,每头牛有一个重量$w_i$和一个强壮程度 $s_i$,定义每头牛的风险值为它上方所有牛的重量之和减去它自身的强壮程度。
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
| #include <iostream> #include <vector> #include <algorithm> using namespace std;
struct Cow { int w, s; };
bool compare(const Cow& a, const Cow& b) { return (a.w + a.s) < (b.w + b.s); }
int main() { int n; cin >> n; vector<Cow> cows(n); for (int i = 0; i < n; i++) { cin >> cows[i].w >> cows[i].s; }
sort(cows.begin(), cows.end(), compare);
long long total_weight = 0; long long max_risk = -1e18; for (int i = 0; i < n; i++) { max_risk = max(max_risk, total_weight - cows[i].s); total_weight += cows[i].w; }
cout << max_risk << endl; return 0; }
|