文章目录
K.贪心
基础知识
1.含义:
①很贪婪:找最优解
②很短视:只会看重眼前的局面不会往后想
2.题目特点:
①跳跃性很强:没有固定的模型,所有贪心题基本上没有什么共性
②可能代码很短,但结论证明很难
3.解题策略:
①找相似
考试的时候看一下这道题跟平时做的有没有相似的,然后套一下相似题目的做法
所以平时多积累归纳总结不同的贪心模型
②猜
考试实在不会就只能猜了,一般贪心题的虽然策略证明很麻烦,但代码都很短,一般可能就是按照按照某个关键字排个序,然后从小到大处理一遍就可以了。
4.一些话:
①贪心题一般都是先猜然后再去证明正确性
②很多贪心问题都可以转换成数学模型,是因为出题人根据数学模型加了些背景出了这些贪心题
例题
一、股票买卖II
1.策略:
(策略就是做法)
遇增则买:依次看相邻两天,只要后一天价格大于前一天的价格,则交易一次,加起他们之间的差值
2.证明:
性质:任何跨度大于一天的交易都可以拆分成若干个跨度等于一天的交易
所以可以独立的看只要每一段上升的全部都加起来

3.代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
int price[N];
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &price[i]); //输入比较长,推荐使用scanf
int res = 0;
for (int i = 0; i + 1 < n; i ++ ) //依次遍历所有跨度为1的交易
{
int dt = price[i + 1] - price[i]; //算交易
if (dt > 0)//只要交易是正的,统计加起来
res += dt;
}
printf("%d\n", res);
return 0;
}
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int a[100010]; //注意题目数据范围
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int sum=0;
for(int i=1;i<=n;i++)
{
if(a[i]<a[i+1])
sum+=(a[i+1]-a[i]);
}
cout<<sum;
return 0;
}
4.总结:
一开始思路:可以从数学坐标轴去理解找到这道题解法,在折线图中,可以发现交易时一定是上升的折线,所以只需要找到拐点,即该点小于两边的点和该点大于两端的点,然后求和算出每段上升折线这两段一小一大两个点的差值即可。代码实现时还要注意特判一下整个两端的边界,分多种情况讨论。
后来发现上述的性质,其实每一段上升的折线都可以分成若干个相邻天数之间的上升端,所以就简单了,直接找比前一个大的小段即可。

二、货仓选址
1.策略:
排序+中位数
①奇数个商店:在中位数
②偶数个商店:中间两个数之间都可
注意:这两个可以合并,偶数个商店时,在中间两个数之间任意点都可,包括这两个点。不管奇数个商店,还是偶数个商店,直接选取中间靠右端点就包括这两种情况。(如果选用中间靠左端点,奇数个时还需单独讨论)。又因为C++中的/是向下取整,所以
当下标从0开始时,mid=a[n/2]
当下标从1开始时,mid=a[n/2+1]
2.证明:
可以发现这个问题可以用数学公式表示,然后利用分组通过几何意义来求解这个公式

(很多贪心问题都可以转换成数学模型,是因为出题人根据数学模型加了些背景出了这些贪心题)
3.代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int n;
int x[N]; //用x表示坐标
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &x[i]); //输入所有的坐标
sort(x, x + n);//依次给所有的坐标排序
int c = x[n / 2]; //求出商店的位置在中点,c++中的/是向下取整
LL res = 0; //注意会不会爆int,用longlong存保险
for (int i = 0; i < n; i ++ ) res += abs(x[i] - c); //求一下到中点的距离
printf("%lld\n", res);
return 0;
}
//奇数偶数个时分开看
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=100010;
int a[N];
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
int mid;
if(n%2!=0)
mid=a[n/2+1];
else
mid=a[n/2];
int sum=0;
for(int i=1;i<=n;i++)
{
sum+=a

最低0.47元/天 解锁文章
1741

被折叠的 条评论
为什么被折叠?



