贪心算法

贪心算法例题及思路

[区间选点]
Q(1):n个区间,每个区间至少一个点,问最少几个点。
[最大不相交区间数量]
衍生Q:n个区间,选取最多无交集的区间。
A(1):按照右端点排序,将点选在右端点。
衍生Q例题
accoders的【一本通提高篇贪心】 活动安排 2032
题意:
求最多无交集区间。
思路:
就是板子 ,按右端点排序,
如果这个区间的左端点大于当前结束时间,就更新结束时间,ans++。
code:
#include<bits/stdc++.h>
using namespace std;
struct node{
int s,f;
bool operator<(const node &W) const{
return f<W.f;
}
}a[1001];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].s>>a[i].f;
}
sort(a+1,a+n+1);
int sum=0,r=0;
for(int i=1;i<n;i++){
if(r<=a[i].s){
r=a[i].f;
sum++;
}
}
cout<<sum;
return 0;
}
Q(1)演变例题:
accoders的【一本通提高篇贪心】 种树2033,一区间内多点
题意 :
每个区间需要至少xi个点有树,区间会重叠。
思路 :
还是按右端点排序,取右端点,先将此区间内已经种上的树苗减去,然后从右端点向左端点种树苗,如果此位置种过了就向前推一个。
code:
#include<bits/stdc++.h>
using namespace std;
struct node{
int l,r,w;
bool operator<(const node &W) const{
return r<W.r;
}
}a[30001];
bool vis[30001];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>a[i].l>>a[i].r>>a[i].w;
}
sort(a+1,a+m+1);
int ans=0;
for(int i=1;i<=m;i++){
int w=a[i].w;
for(int j=a[i].l;j<=a[i].r;j++){
if(!w){
break;
}
if(vis[j]){
w--;
}
}
if(!w){
continue;
}
for(int j=a[i].r;j>=a[i].l;j--){
if(!w){
break;
}
if(!vis[j]){
ans++;
vis[j]=1;
w--;
}
}
}
cout<<ans;
return 0;
}
[区间覆盖]
Q(2):给定一个大区间,问多少小区间能覆盖大区间。
A(2):小区间按照左端点排序,选右端点最靠右且左端点不大于大区间左端点的,然后将该小区间的右端点设为大区间左端点,重复上述操作。
Q(2)板子:
accoders的【贪心区间问题】907. 区间覆盖 10110
code:
#include<bits/stdc++.h>
using namespace std;
struct node{
int l,r;
bool operator <(const node &W) const{
return l<W.l;
}
}a[100010];
int main(){
int l,r;
cin>>l>>r;
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].l>>a[i].r;
}
sort(a+1,a+n+1);
int i=1,ans=0;
while(l<r){
int vis=-1e9,j;
for(j=i;j<=n;j++){
if(a[j].l<=l){
vis=max(vis,a[j].r);
}else{
break;
}
}
if(l<r&&a[i].l>l){
cout<<-1;
return 0;
}
ans++;
l=vis;
i=j;
}
cout<<ans;
return 0;
}
Q(2)例题
accoders的【一本通提高篇贪心】 喷水装置2034,勾股定理加大区间覆盖
题意:
二维大区间覆盖。
思路:
通过勾股定理求出区间左端点和右端点,不考虑半径不大于w/2的喷头,然后进行求大区间覆盖。
code:
#include<bits/stdc++.h>
using namespace std;
struct node{
double l,r;
bool operator<(const node &W) const{
return l<W.l;
}
}a[15001];
int cnt=0;
int n;
double l,w;
int main(){
int T;
cin>>T;
while(T--){
cnt=0;
cin>>n>>l>>w;
double w2=w/2.0;
for(int i=1;i<=n;i++){
double x,y;
cin>>x>>y;
if(y<=w/2){
continue;
}
a[++cnt].l=x-sqrt(y*y-w*w/4);
a[cnt].r=x+sqrt(y*y-w*w/4);
}
sort(a+1,a+cnt+1);
double s=0,e=l;
int i=1,ans=0,t=0;
while(s<e){
double vis=-2e9;
int j;
for(j=i;j<=cnt;j++){
if(a[j].l<=s){
vis=max(vis,a[j].r);
}else{
break;
}
}
if(s<e&&vis<s){
cout<<-1<<"\n";
t=1;
break;
}
ans++;
s=vis;
i=j;
}
if(!t)cout<<ans<<"\n";
}
return 0;
}
[区间分组]
Q(3):n个区间,分成几组,组内无交集,问最少能分成几组。
A(3):按左端点排序
Q(3)例题:
accoders【贪心区间问题】906. 区间分组10109
单纯板子
code:
#include<bits/stdc++.h>
using namespace std;
struct node{
int l,r;
bool operator <(const node &W) const{
return l<W.l;
}
}a[100010];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].l>>a[i].r;
}
sort(a+1,a+n+1);
priority_queue<int, vector<int>, greater<int> > q;
for(int i=1;i<=n;i++){
if(q.empty()||q.top()>=a[i].l){
q.push(a[i].r);
}else{
q.pop();
q.push(a[i].r);
}
}
cout<<q.size();
return 0;
}
贪心其他例题:
1.
accoders的【一本通提高篇贪心】 加工生产调度2035
luogu 的 P1248 加工生产调度
思路:
先求出每一个物品的AB时间最小值,然后排序,
将A机器时间从前向后排入q序列,将B机器时间从后向前排入q序列,
最后模拟求得总时间。
code(按照洛谷题干写):
#include<bits/stdc++.h>
using namespace std;
struct node{
int w,id;
bool operator<(const node &W) const{
return w<W.w;
}
}s[1001];
int a[1001],b[1001],n;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
for(int i=1;i<=n;i++){
s[i].w=min(a[i],b[i]);
s[i].id=i;
}
sort(s+1,s+n+1);
int q[1001]={};
int l=0,r=n+1;
for(int i=1;i<=n;i++){
if(s[i].w==a[s[i].id]){
q[++l]=s[i].id;
}else{
q[--r]=s[i].id;
}
}
int tia=0,tib=0;
for(int i=1;i<=n;i++){
tia+=a[q[i]];
tib=max(tia,tib);
tib+=b[q[i]];
}
cout<<tib<<"\n";
for(int i=1;i<=n;i++){
if(q[i]){
cout<<q[i]<<" ";
}
}
return 0;
}
2.
accoders的【一本通提高篇贪心】 智力大冲浪2036
luogu的P1230 智力大冲浪
思路:
将罚金从大到小排序,然后从最后实现时间向前推,若无时间可插则扣罚金。
code:
#include<bits/stdc++.h>
using namespace std;
struct node{
int ti,m;
bool operator <(const node &W) const{
return m>W.m;
}
}a[501];
int vis[501];
int main(){
int m,n;
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>a[i].ti;
}
for(int i=1;i<=n;i++){
cin>>a[i].m;
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
int f=0;
for(int j=a[i].ti;j>=1;j--){
if(!vis[j]){
vis[j]=1;
f=1;
break;
}
}
if(!f){
m-=a[i].m;
}
}
cout<<m;
return 0;
}
3.
accoders的【一本通提高篇贪心】 钓鱼2041
luogu的P1717 钓鱼
思路:
不走回头路,只向前走,然后向大根堆中压入路过池塘的鱼的数量,每次弹出最多的然后减去减少的,
然后重新压入堆 ,重复以上过程求走到每个池塘后的max。
测后自写代码:www.luogu.com.cn/paste/j83dvxau
code:
#include<bits/stdc++.h>
using namespace std;
int ff[101],df[101],ti[101];
struct node{
int id,w;
bool operator <(const node &W) const{
return w<W.w;
}
};
int main(){
int n,h;
cin>>n;
cin>>h;
h=h*12;
node t;
int ans=-1,lt,sum;
for(int i=1;i<=n;i++){
cin>>ff[i];
}
for(int i=1;i<=n;i++){
cin>>df[i];
}
for(int i=1;i<n;i++){
cin>>ti[i];
ti[i]+=ti[i-1];//前缀和
}
for(int i=1;i<=n;i++){
lt=h-ti[i-1],sum=0;
if(lt<=0){
break;
}
priority_queue<node> q;
for(int j=1;j<=i;j++){
q.push({j,ff[j]});
}
for(int j=1;j<=lt;j++){
t=q.top();
q.pop();
if(t.w<0){
break;
}
sum+=t.w;
q.push({t.id,t.w-df[t.id]});
}
ans=max(ans,sum);
}
cout<<ans;
return 0;
}
4.
accoders的【一本通提高篇贪心】 糖果传递
luogu的P2512 [HAOI2008] 糖果传递
code:
#include<bits/stdc++.h>
using namespace std;
int a[1001001];
long long c[1001001],sum;
long long n;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
long long ave=sum/n;
for(int i=n;i>=1;i--){
c[i]=c[i+1]+ave-a[i];
}
c[1]=0;
sort(c+1,c+1+n);
long long ans=0;
for(int i=1;i<=n;i++){
ans+=abs(c[i]-c[(n+1)/2]);
}
cout<<ans<<"\n";
return 0;
}
posted @   lbh123  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示