第六章 贪心 完结
Posted 辉小歌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第六章 贪心 完结相关的知识,希望对你有一定的参考价值。
贪心类题型没有固定的模板只有多做题,总结经验。
905. 区间选点
https://www.acwing.com/problem/content/description/907/
本题和区间合并那种题几乎一样的思路,不过还是有差别的。
首先:按左端点从小到达排,这是没有悬念的必须做的。
这时候分析,会有如下几种情况:
情况一:
这种包含的情况,我们要选小的,因为我们要的是公共部分。
情况二:
这种相交的情况选,相交的。
情况三:
不相交的情况选b,个数加1。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct student
{
int x,y;
}stu[N];
bool cmp(student a,student b)
{
return a.x<b.x;
}
int main(void)
{
int n; cin>>n;
for(int i=0;i<n;i++) cin>>stu[i].x>>stu[i].y;
sort(stu,stu+n,cmp);
int ans=1;
int startx=stu[0].x,endx=stu[0].y;
for(int i=1;i<n;i++)
{
if(stu[i].x<=endx&&stu[i].y<=endx) startx=stu[i].x,endx=stu[i].y;
else if(stu[i].x<=endx&&stu[i].y>endx) startx=stu[i].x;
else ans++,startx=stu[i].x,endx=stu[i].y;
}
cout<<ans<<endl;
return 0;
}
方法二 从小到大排序右端点:
因为我们选右端点,才可能尽量大的覆盖掉后面的区间
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=1e5+10;
struct node
{
int x,y;
}Node[N];
bool cmp(node a,node b)
{
return a.y<b.y;
}
int main(void)
{
int n; cin>>n;
for(int i=0;i<n;i++) cin>>Node[i].x>>Node[i].y;
sort(Node,Node+n,cmp);
int ans=0;
int flag=-1e9;
for(int i=0;i<n;i++)
{
if(flag<Node[i].x) ans++,flag=Node[i].y;
}
cout<<ans<<endl;
return 0;
}
908. 最大不相交区间数量
https://www.acwing.com/problem/content/910/
老规矩:左端点从小到大排序
第一种情况:
这种得选a,这样右边的区间的选择范围才会更大。
第二种情况:
此时不用变,还是a这样才会有更大的空间。
第三种情况:
选b,数量加1
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct student
{
int x,y;
}stu[N];
bool cmp(student a,student b)
{
return a.x<b.x;
}
int main(void)
{
int n; cin>>n;
for(int i=0;i<n;i++) cin>>stu[i].x>>stu[i].y;
sort(stu,stu+n,cmp);
int ans=1;
int startx=stu[0].x,endx=stu[0].y;
for(int i=1;i<n;i++)
{
if(stu[i].y<endx) startx=stu[i].x,endx=stu[i].y;
else if(stu[i].x>endx) ans++,startx=stu[i].x,endx=stu[i].y;
}
cout<<ans<<endl;
return 0;
}
方法二:从小到大排序右端点
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct node
{
int x,y;
}Node[N];
bool cmp(node a,node b)
{
return a.y<b.y;
}
int main(void)
{
int n; cin>>n;
for(int i=0;i<n;i++) cin>>Node[i].x>>Node[i].y;
sort(Node,Node+n,cmp);
int ans=0;
int flag=-1e9;
for(int i=0;i<n;i++)
{
if(Node[i].x>flag) ans++,flag=Node[i].y;
}
cout<<ans<<endl;
return 0;
}
906. 区间分组 【有意思】
https://www.acwing.com/problem/content/description/908/
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct node
{
int x,y;
}Node[N];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main(void)
{
int n; cin>>n;
for(int i=0;i<n;i++) cin>>Node[i].x>>Node[i].y;
sort(Node,Node+n,cmp);
priority_queue<int, vector<int>, greater<int> >heap;
for(int i=0;i<n;i++)
{
if(heap.empty()||heap.top()>=Node[i].x)//组为空,或者任何一个组内都放不下
{
heap.push(Node[i].y);
}
else if(heap.top()<Node[i].x)//可以放进组内
{
heap.pop();//将原来的区间的最右值更新
heap.push(Node[i].y);
}
}
cout<<heap.size()<<endl;
return 0;
}
907. 区间覆盖【有意思】
https://www.acwing.com/problem/content/description/909/
对于可以覆盖之前的,我们要选它们中最长的。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct node
{
int x,y;
}Node[N];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main(void)
{
int st,ed; cin>>st>>ed;
int n; cin>>n;
for(int i=0;i<n;i++) cin>>Node[i].x>>Node[i].y;
sort(Node,Node+n,cmp);
int res=0;
bool flag=false;
for(int i=0;i<n;i++)
{
int j=i,r=-1e9;
while(j<n&&Node[j].x<=st)//找到最大的右端点
{
r=max(r,Node[j].y);
j++;
}
if(r<st)//说明r没有更新,说明这两段没有公共部分,故不能覆盖
{
res=-1;
break;
}
res++;
if(r>=ed)//覆盖完了
{
flag=true;
break;
}
st=r;//更新
i=j-1;
}
if(!flag) cout<<-1<<endl;
else cout<<res<<endl;
return 0;
}
148. 合并果子
https://www.acwing.com/problem/content/description/150/
方法:每次选最小的两个合并。
小根堆做法
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
int main(void)
{
priority_queue<int, vector<int>, greater<int> >heap;
int n; cin>>n;
while(n--)
{
int x; cin>>x;
heap.push(x);
}
long long int res=0;
while(heap.size()>1)
{
int a=heap.top(); heap.pop();
int b=heap.top(); heap.pop();
res+=a+b;
heap.push(a+b);
}
cout<<res<<endl;
return 0;
}
大根堆做法
#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
int main(void)
{
int n; cin>>n;
priority_queue<int> heap;
while(n--)
{
int x; cin>>x;
heap.push(-x);
}
long long int res=0;
while(heap.size()>1)
{
int a=heap.top(); heap.pop();
int b=heap.top(); heap.pop();
res+=(-a-b);
heap.push(-(-a-b));
}
cout<<res<<endl;
return 0;
}
913. 排队打水
https://www.acwing.com/problem/content/description/915/
思路: 由于若把时间长的放在后面接水,那么就较少人等,所以排序+贪心即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
long long int a[N],s[N];
int main(void)
{
int n; cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
long long int sum=0;
for(int i=1;i<=n-1;i++) s[i]=s[i-1]+a[i],sum+=s[i];
//1代表的就是第二个人的等待时间,第一个人的等待时间为零
cout<<sum<<endl;
return 0;
}
104. 货仓选址
https://www.acwing.com/problem/content/description/106/
选中间的位置最优
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N],sum;
int main(void)
{
int n; cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
int area=a[n/2];
for(int i=0;i<n;i++) sum+=abs(area-a[i]);
cout<<sum<<endl;
return 0;
}
125. 耍杂技的牛
https://www.acwing.com/problem/content/description/127/
按其和从小到大排序
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct student
{
int w,s;
}以上是关于第六章 贪心 完结的主要内容,如果未能解决你的问题,请参考以下文章