目录
声明:
本系列博客是《算法竞赛进阶指南》+《算法竞赛入门经典》+《挑战程序设计竞赛》的学习笔记,主要是因为我三本都买了按照《算法竞赛进阶指南》的目录顺序学习,包含书中的少部分重要知识点、例题解题报告及我个人的学习心得和对该算法的补充拓展,仅用于学习交流和复习,无任何商业用途。博客中部分内容来源于书本和网络(我尽量减少书中引用),由我个人整理总结(习题和代码可全都是我自己敲哒)部分内容由我个人编写而成,如果想要有更好的学习体验或者希望学习到更全面的知识,请于京东搜索购买正版图书:《算法竞赛进阶指南》——作者李煜东,强烈安利,好书不火系列,谢谢配合。
下方链接为学习笔记目录链接(中转站)
贪心
贪心是一种在每一次决策时都采用当前意义下最优策略的算法,因此,使用贪心算法要求问题的整体最优性可以由局部最优性导出。
贪心算法的正确性需要证明,常见的证明手段有:
- 微扰(邻项交换) 证明在任意局面下,任何对局部最优策略的微小改变都会造成整体结果变差,经常用于以排序为贪心策略的证明。
- 范围缩放 证明任何对局部最优策略作用范围的扩展都不会造成整体结果变差。
- 决策包容性
证明在任意局面下,做出局部最优策略以后,在问题状态空间中的可达到集合包含了做出其他任何决策之后的可到达集合。换言之,这个局部最优解提供的可能性包含其他所有策略提供的可能性。 - 反证法
- 数学归纳法
0. USACO07NOV Sunscreen
洛谷题目链接 :https://www.luogu.com.cn/problem/P2887
其实本题可以看成区间覆盖问题,即求线段最多覆盖多少点,线段按右端点排序,防晒霜按防护值排序,只不过这里的线段有数量而已。
%%%yxc大佬,看完他的题解学到了一些实用的map的操作。
戳我看题解
整理了一下map 的操作:我是博客链接
yxc大佬的证明太强了,其实就是如果按照min排序,那么对于每一个防晒霜来说,不低于当前的牛的min,就一定不低于下一头牛的min,对于当前牛可用的两种防晒霜x和y来说,如果 s p f [ x ] < s p f [ y ] spf[x]<spf[y] spf[x]<spf[y]那么对于后面的牛来说,只能出现“x,y都能用”,“x,y都不能用”,和“x能用y不能用”这三种情况,因此这时选择用掉最大的是最优的。定好了一个边界以后,每次对于当前的牛,直接利用map中的upper_bound直接找到第一个大于max的防晒霜,并–找到第一个小于等于当前牛max的防晒霜,用掉。如果这种的防晒霜用完了,就从map 里erase掉。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<map>
#define ls (p<<1)
#define rs (p<<1|1)
#define over(i,s,t) for(register long long i=s;i<=t;++i)
#define lver(i,t,s) for(register long long i=t;i>=s;--i)
//#define int __int128
using namespace std;
typedef long long ll;//全用ll可能会MLE或者直接WA,全部换成int看会不会A,别动这里!!!
const ll N=2507;
const ll mod=1e9+7;
const double EPS=1e-5;//-10次方约等于趋近为0
int n,m;
pair<int,int>cow[N];
int main()
{
cin>>n>>m;
map<int,int>spfs;
over(i,1,n)scanf("%d%d",&cow[i].first,&cow[i].second);
over(i,1,m){
int spf,cover;
scanf("%d%d",&spf,&cover);
spfs[spf]+=cover;
}
sort(cow+1,cow+1+n);
int res=0;
spfs[0]=spfs[1001]=n;
for(int i=n;i>=1;--i){
auto spf=spfs.upper_bound(cow[i].second);
spf--;//这里的spf是map<>spfs的一个iterator,第一个大于cow[i].max的防晒霜
//--之后就是最后一个小于等于cow[i].max的防晒霜了
if(spf->first>=cow[i].first){
res++;
if(--spf->second==0)
spfs.erase(spf);
}
}
printf("%d\n",res);
return 0;
}
1.USACO06FEB Stall Reservations (贪心)
题目链接:https://www.luogu.com.cn/problem/P2859
输入样例:
5
1 10
2 4
3 6
5 8
4 7
输出样例:
4
1
2
3
2
4
贪心的思路还是很好想很基础的,但是这道题代码写起来脑壳痛,其中的细节颇多,特别是这个queue里的bug找的我头疼,遂写成博客以警惕自己
你见过哪些意想不到的bug ?(常见代码使用误区,下次一定还犯)
这道题剩下的也没什么,就是要注意输出每头牛的组的时候要+1,因为这里是从0开始的
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
#define ls (p<<1)
#define rs (p<<1|1)
#define over(i,s,t) for(register int i=s;i<=t;++i)
#define lver(i,t,s) for(register int i=t;i>=s;--i)
//#define int __int128
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;//全用ll可能会MLE或者直接WA,全部换成int看会不会A,别动这里!!!
const int N=50010;
const ll mod=1e9+7;
const double EPS=1e-5;//-10次方约等于趋近为0
#define a cows
#define q heap
#define ans id
int ans[N];
pair<PII, int>a[N];
int n,m;
int main()
{
cin>>n;
for (int i = 0; i < n; i ++ ){
cin>>a[i].first.first>>a[i].first.second;
a[i].second=i;
}
sort(a,a+n)