贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解。
核心的处理在于:最优子结构的存在,即部分最优解合起来是整体最优解。
以题目进行分析:
P7095 [yLOI2020] 不离https://www.luogu.com.cn/problem/P7095
PS首先感谢一下写题解的大佬,我一开始是真的不会做,按照它的代码慢慢摸索在,终于会了。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
#define RG register int
#define ll long long
#define ull unsigned long long
#define int long long
const int maxn = 100010;
struct equipment
{
int power, spirit, padd, sadd;
inline bool operator<(const equipment &x) const
{
return spirit ^ x.spirit ? spirit > x.spirit : sadd ^ x.sadd ? sadd < x.sadd : padd < x.padd;
}
} Equip[maxn];
template <class T>
inline void read(T &x)
{
char c = getchar();
int w = 0;
x = 0;
while (!isdigit(c))
w |= c == '-', c = getchar();
while (isdigit(c))
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
if (w)
x = -x;
}
template <typename T>
inline void print(T x)
{
if (x > 9)
print(x / 10);
putchar(x % 10 | 48);
}
priority_queue<equipment> q;
bool cmp(equipment a, equipment b)
{
return a.power ^ b.power ? a.power < b.power : a.padd > b.padd;
}
signed main()
{
int t, number;
read(t);
read(number);
for (register int i = 0; i < number; i++)
{
read(Equip[i].power), read(Equip[i].spirit), read(Equip[i].padd), read(Equip[i].sadd);
}
sort(Equip, Equip + number, cmp);
int ans = 0, a = 0;
for (register int i = 0; i < number; i++)
{
if (a < Equip[i].power)
{
ans = ans + Equip[i].power - a;
a = Equip[i].power;
}
a = a + Equip[i].padd;
}
print(ans);
putchar(' ');
int ans2 = 0, b = 0; //最小的穿戴精神要求与此时的精神,此时的力量
//我想要在ans已经确定的前提下利用优先对列进行做题,如何解决?
//为什么不把ans设为初值呢?
for (register int i = 0; i < number; i++)
{
if (Equip[i].power <= ans)
q.push(Equip[i]);
else
{
while (ans < Equip[i].power)
{
int padd = q.top().padd, spirit = q.top().spirit, sadd = q.top().sadd;
q.pop();
if (b < spirit)
{
ans2 = ans2 + spirit - b;
b = spirit;
}
b = b + sadd;
ans += padd;
}
q.push(Equip[i]);
}
if (i == number - 1)
{
while (!q.empty())
{
int spirit = q.top().spirit, sadd = q.top().sadd;
q.pop();
if (b < spirit)
{
ans2 = ans2 + spirit - b;
b = spirit;
}
b = b + sadd;
}
}
}
print(ans2);
system("pause");
return 0;
}
//终于给我过了,哈哈哈哈哈
//难死我了= =
//掌握到了一些精髓
//贪心算法中优先队列的镶嵌使用,通过sort获得第一限制条件能够得到的结果
//再通过priority_queue实现在第一个限制条件下的第二个限制条件的完成
//拓展一下,如果要求有三个限制条件,又或者n个限制条件呢?
//在完成第二个限制条件后,以第一个,第二个为约束条件进行搜索即可,ok!
这道题目的核心问题,如何在第一个限制条件,即保证初始力量最小的条件下筛选出初始精神最小。
对于这个问题,优先队列是一个非常好的办法,其本身只有logN的复杂度,在内部设立一个相对于筛选环境就行。
例题2:例题没有了。。。
给定一个n,下面有n个数据,每行有a,b,c三个数字,保证a+b+c>=0
求初始的资金c,能遍历完全部的数据。
由于最后的值一定大于0,所以我们只需要通过每个数据的t=min(a,a+b)进行筛选就可以,我们要保证最小的启动资金先被筛选到。
正在施工。。。。。。。。。。