贪心的思想即在每一步中,采取某种短视的做法达到局部最优解,在完成所有步骤后,就达到了全局的最优解。
这种算法属于较难的一种,既没有固定的套路/模板,而且某些贪心问题也比较难以证明,在实际做题时,需要多积累一些贪心模型,遇到实际的问题时,尽量往已经收悉的模型上靠,这样能降低一些解题难度。
例题1:股票买卖
题目链接:acwing.1055
数据范围为十万,所以只能选用时间复杂度为n或者nlogn的算法。
值得注意的是,很多贪心问题在实现的时候,都是先排序,然后再采用某种策略进行选择。(这题中并没有排序)
在这题中,由于可以多次操作买入与卖出,所以利用一个指针指向下一个price,如果下一个price增加,就买入,否则就卖出。
实现的代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
int q[N];
int n;
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
scanf("%d", &q[i]);
int w; //w为手中所持股票的价值
int pro=0; //利润
for (int i = 0; i + 1 < n; i++)
{
if (q[i + 1] > q[i]) //只要下一天的价值比当天的价值高, 就赚一次两天的差价(贪心思想的体现)
{
pro += q[i + 1] - q[i];
}
}
cout << pro<<endl;
}
例题2:仓库选址
题目链接:acwing.104
在这题中,闫老板提到了一个实用的解题技巧,对于复杂的问题,可以先举例几个简单的情况,例如在本题中,可以先思考在只有一个或者两个货仓的时候如何选址。
很显然,如果只有一家商店,可以直接将地址选在这个货舱之上,如果有两个上商店,就可以将货舱置于两家商店之间的任意位置。
于是可以猜想:
如果有奇数个商店,可以把仓库建在中位数上
如果有偶数个商店,可以把仓库建在中间的两个商店之间
(这个猜想是正确的,可以利用绝对值不等式加以证明,具体的证明过程可以参考闫老板的视频)
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 100010;
long long q[N]; //q[N]存储的是坐标
int n;
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
scanf("%lld", &q[i]);
sort(q, q + n);
long long int base;
base = q[n / 2];
long long res = 0;
for (int i = 0; i < n; i++)
res += abs(q[i] - base);
cout << res << endl;
return 0;
}