前言:贪心一般没有固定的套路或模板,只能不断尝试。
每次我们选择局部问题的最优解不断走下去以达到全局的最优解
代码一般比较好写但证明难
一般直觉上想出一个做法然后证明为什么是正确的
猜!
第一章
区间选点
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
struct Range
{
int l, r;
bool operator< (const Range &W)const
{
return r < W.r;
}
}range[N]; // 重载-range中每个元素存放一个区间的左右端点
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
int l, r;
scanf("%d%d", &l, &r);
range[i] = {l, r};
}
sort(range, range + n); // 将所有区间从大到小排序
int res = 0, ed = -2e9;
for (int i = 0; i < n; i ++ )
// 当前处理区间的左端点在上一个选择区间右端点的右侧(出现间断区间),则新增一个选择区间
// ed存放上一个选择区间的右端点并res++ 后更让新为处理区间的右端点值
if(range[i].l > ed)
{
res ++ ;
ed = range[i].r;
}
printf("%d\n", res);
return 0;
}
区间分组
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010;
int n;
struct Range
{
int l, r;
bool operator< (const Range &W)const
{
return l < W.l;
}
}range[N];
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
int l, r;
scanf("%d%d", &l, &r);
range[i] = {l, r};
}
sort(range, range + n);
priority_queue<int, vector<int>, greater<int>> heap;
for (int i = 0; i < n; i ++ )
{
auto r = range[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;
if(heap.size()) cout << "YES";
else cout << "NO" << endl;
return 0;
}
区间覆盖
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 100010;
int n;
struct Range
{
int l, r;
bool operator< (const Range &W)const
{
return l < W.l; // 按左端点从小到大排序每个区间
}
}range[N];
int main()
{
int st, ed;
scanf("%d%d", &st, &ed); // 线段区间做右端点
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
int l, r;
scanf("%d%d", &l, &r);
range[i] = {l, r};
}
sort(range, range + n);
int res = 0;
bool success = false;
for (int i = 0; i < n; i ++ ) // 遍历n个区间
{
// j依次从第0 1 .. n个区间开始,判断第0 1...
int j = i, r = -2e9;
// 双指针找到从第j~n个区间中最后一个可以覆盖st的区间并更新r为所找到区间的右端点
while(j < n && range[j].l <= st)
{
r = max(r, range[j].r);
j ++ ;
}
if(r < st) // 若找到区间的右端点也在st左侧无法覆盖,不可计数
{
res = -1;
break;
}
res ++ ; // 当前区间与st-ed有交集,res统计所需最小所需区间个数
if(r >= ed)
{
success = true;
break;
}
st = r; // 更新r为所找到区间右端点并往后查找覆盖新st的区间
i = j - 1; // 返回for i ++ 一次并判断当前区间是否能覆盖ed
}
if(!success) res = -1;
printf("%d\n", res);
return 0;
}
合并果子(Huffman树)
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int main()
{
int n;
scanf("%d", &n);
priority_queue<int, vector<int>, greater<int>> heap;
while (n -- )
{
int x;
scanf("%d", &x);
heap.push(x);
}
int res = 0;
while(heap.size() > 1)
{
int a = heap.top(); heap.pop();
int b = heap.top(); heap.pop();
res += a + b;
heap.push(a + b);
}
printf("%d\n", res);
return 0;
}
第二章
排队打水
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int main()
{
int n, a[N];
scanf("%d", &n);
for(int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
sort(a, a + n);
long long res = 0;
for(int i = 0; i < n; i ++ ) res += a[i] * (n - i - 1);
printf("%lld\n", res);
return 0;
}
货仓选址
仓库点的选择
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
int dis[N];
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i ++ ) scanf("%d", &dis[i]);
sort(dis, dis + n);
int res = 0;
for(int i = 0; i < n; i ++ ) res += abs(dis[i] - dis[n / 2]);
printf("%d\n", res);
return 0;
}
耍杂技的牛
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 50010;
int n;
PII cow[N]; // 由于需要排序用pair
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i ++ )
{
int w, s;
scanf("%d%d", &w, &s);
cow[i] = {w + s, w};
}
sort(cow, cow + n); // 按 wi+si < w(i+1) + s(i+1) 排序
int res = -2e9, sum = 0;
for(int i = 0; i < n; i ++ )
{
int w = cow[i].second, s = cow[i].first - w;
res = max(res, sum - s); // 计算危险系数max值
sum += w; // 统计前i-1头牛的体重总和
}
printf("%d\n", res);
return 0;
}