贪心
1. 简介
基本原理:每一步都选择局部最优解,并且尽量不考虑对后续的影响,最终达到全局最优解
局限性:不能保证获得全局最优解,但在某些问题上具有高效性
“分类讨论”,“最小代价”,“最大价值”
贪心题型太多,要多练
2. 例题
最小化战斗力差距
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
const int N = 1e5 + 10;
ll a[N], b[N];
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
sort(a + 1, a + n + 1);
ll res = 0x3fffffffffffff;
for(int i = 2; i <= n; i ++ )
{
b[i] = a[i] - a[i - 1];
res = min(res, b[i]);
}
cout << res << endl;
return 0;
}
谈判
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
priority_queue<ll, vector<ll>, greater<ll>> pq;
int main()
{
int n; cin >> n;
for(int i = 1; i <= n; i ++ )
{
ll x; cin >> x;
pq.push(x);
}
ll ans = 0;
while(pq.size() > 1)
{
ll x = pq.top(); pq.pop();
ll y = pq.top(); pq.pop();
ans += x + y;
pq.push(x + y);
}
cout << ans << endl;
return 0;
}
优先队列(priority_queue):一个有权值的“队列”
表现为一个以vector表现的完全二叉树
权值高的排在前面
priority_queue<Type, Container, Functional>
Type代表数据类型,Container代表容器类型,缺省状态为vector; Functional是比较方式
默认采用大顶堆
大堆:
priority_queue<int,vector<int>, less<int>> q;
小堆:
priority_queue<int,vector<int>, greater<int>> q;
自定义比较函数:
struct cmp
{
bool operator()(int a, int b)
{
return a > b;
}
}
priority_queue<int, vector<int>, cmp> q;
纪念品分组
思路:最大配最小,配不上的话最大单独一组
双指针实现:
#include <bits/stdc++.h>
using namespace std;
const int N = 30010;
int a[N];
int main()
{
int w, n;
cin >> w >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
sort(a + 1, a + n + 1);
int l = 1, r = n, ans = 0;
while(l <= r)
{
ans ++ ;
if(l == r) break;
if(a[l] + a[r] <= w)
{
l ++ ;
r -- ;
}else r -- ;
}
cout << ans << endl;
return 0;
}
分糖果
思路:分类讨论
- 字符串全相等:尽量平均分
s[x] == s[1]
:前x - 1
个一人一个,x ~ n
一人独享s[x] != s[1]
:前x
个一人一个,后面x ~ n
这一坨扔给第一个人
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
char s[N];
int main()
{
int n, x;
cin >> n >> x;
cin >> s + 1;
sort(s + 1, s + n + 1);
if(s[1] == s[n])
{
// 尽量平均分,加上 (n % x ? 1 : 0)
for(int i = 1; i <= n / x + (n % x ? 1 : 0); i ++ ) cout << s[1];
}else if(s[1] == s[x])
{
for(int i = x; i <= n; i ++ ) cout << s[i];
}else cout << s[x];
return 0;
}
最大的卡牌价值
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 9;
ll a[N], b[N];
vector<ll> c;
bool cmp(const ll &m, const ll &n)
{
return m > n;
}
int main()
{
ll n, k;
cin >> n >> k;
ll ans = 0;
for(ll i = 1; i <= n; i ++ )
{
cin >> a[i];
ans += a[i];
}
for(ll i = 1; i <= n; i ++ ) cin >> b[i];
for(ll i = 1; i <= n; i ++ )
{
if(b[i] > a[i])
{
c.push_back(b[i] - a[i]);
}
}
sort(c.begin(), c.end(), cmp);
ll t = min(k, (ll)c.size());
for(ll i = 0; i < t; i ++ )
{
ans += c[i];
}
cout << ans << endl;
}
明日方舟大作战!
与其说是贪心,我觉得更像是背包dp
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int atk[N], cst[N], f[N];
int main()
{
int n, m, B;
cin >> n >> m >> B;
for(int i = 1; i <= n; i ++ ) cin >> atk[i] >> cst[i];
for(int i = 1; i <= n; i ++ )
{
for(int j = B; j >= cst[i]; j -- )
{
f[j] = max(f[j], f[j - cst[i]] + atk[i]);
}
}
int max_life = 0;
for(int i = 1; i <= m; i ++ )
{
int life;
cin >> life;
max_life = max(max_life, life);
}
int max_atk = f[B];
if(max_atk == 0)
{
cout << -1 << endl;
return 0;
}
int rounds = (int) ceil((double) max_life / max_atk);
cout << rounds << endl;
return 0;
}
值得注意的是这个向上取整的方式:int rounds = (int) ceil((double) max_life / max_atk);
首先,将 max_life 转换为双精度浮点数(double),然后计算 max_life 除以 max_atk 的结果,得到一个双精度浮点数(double)值。
接下来,使用 ceil() 函数将结果向上取整,以得到一个整数值。最后,将结果强制转换回整数类型(int),并将结果赋值给 rounds 变量。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。