贪心算法
贪心算法例题及思路
[区间选点] 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; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!