贪心算法
几乎所有题都应用到了排序,sort,min,*min_element
找出最快/慢,最大/小(一般先解决最不好解决的,即:最大和最慢)
- 把普遍进行排序
- 用个别的最优解映射出普遍的最优解
3.比如先考虑最大的(活动选择),先考虑最慢的(过河),或者用两者的普遍性规律来解题(区域覆盖)
(30条消息) 从零开始学贪心算法_houjingyi233的博客-CSDN博客_贪心算法
贪⼼算法⼀般分为如下四步:
1.将问题分解为若⼲个⼦问题
2.找出适合的贪⼼策略
3.求解每⼀个⼦问题的最优解
4.将局部最优解堆叠成全局最优解
1.活动选择问题
这是《算法导论》上的例子,也是一个非常经典的问题。有n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi 。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。
局部最优解:最小的终点值进行排序,再对应起点的值
#include<bits/stdc++.h> using namespace std; int n; struct node { int start; int end; }act[1000]; bool cmp(node a,node b) { return a.end<b.end; } int tx() { int i=1,num=1; for(int j=2;j<=n;j++) { if(act[i].end<=act[j].start) { i=j; num++; } } return num; } int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>act[i].start>>act[i].end; } sort(act+1,act+n+1,cmp); int ans=tx(); cout<<ans; return 0; }
2.找钱
局部最优解:从大到小依次比较看看money是否大于value[i];
#include<bits/stdc++.h> using namespace std; int value[7]={1,2,5,10,20,50,100}; int Count[7]={3,0,2,1,0,3,5}; int solve(int money) { int num=0; for(int i=6;i>=0;i--) { int c=min(money/value[i],Count[i]);//太强了 money=money-c*value[i]; num=num+c; } if(money>0) return -1; else return num; } int main() { int money; cin>>money; int ans=solve(money); cout<<ans; return 0; }
3.再论背包问题
只讨论了比例
#include<bits/stdc++.h> using namespace std; const int N=5; void bili(float M,float w[],float v[],float x[]) { int i; for(i=0;i<N;i++) { if(M>w[i]) { x[i]=1; M=M-w[i]; } else break; } if(i<N) x[i]=M/w[i]; } int main() { float M=50; float w[]={0,10,30,20,5};//从小到大排好序 float v[]={0,200,400,100,10}; float x[N]={0}; bili(M,w,v,x); for(int i=0;i<N;i++) { cout<<x[i]<<" "; } return 0; }
4.分机调度
max_element、min_element用法详解
min_element 和 max_element
头文件:#include<algorithm>
作用:返回容器中最小值和最大值的指针。max_element(first,end,cmp);其中cmp为可选择参数!
#include<cstdio> #include<vector> #include<algorithm> using namespace std; int main() { int a[4]={1,2,3,4}; vector<int> v={1,2,3,4}; int m1=*max_element(a,a+4); int m2=*min_element(v.begin(),v.end()); printf("%d %d",m1,m2); return 0; } max_element返回指定容器或数组范围[begin,end)内的最大值的迭代器或指针; min_element返回指定容器或数组范围[begin,end)内的最小值的迭代器或指针; 注意返回的是迭代器或指针哈~,不是直接返回值。 #include<bits/stdc++.h> using namespace std; int speed[1000]; int w[1000]; int m,n; bool cmp(int x,int y) { return x>y; } void solve() { for(int i=0;i<n;i++) { *min_element(w,w+m)+=speed[i]; } cout<<*max_element(w,w+m)<<endl; } int main() { cin>>n>>m; memset(speed,0,sizeof(speed)); memset(w,0,sizeof(w)); for(int i=0;i<n;i++) { cin>>speed[i]; } sort(speed,speed+n,cmp); solve(); return 0; }
5.小船过河
只要n>3那每次的任务都是:把最速度(speed)最慢的两个人送过去,并且保证最快的回来,有两种方法,每次都讨论哪一种更快。
#include<bits/stdc++.h> using namespace std; int n,sum=0; int speed[1000]; bool cmp(int x,int y) { return x<y; } int main() { cin>>n; for(int i=0;i<n;i++) cin>>speed[i]; sort(speed,speed+n,cmp); while(n>3) { sum+=min(speed[1]+speed[0]+speed[n-1]+speed[1],speed[n-1]+speed[0]+speed[n-2]+speed[0]); n-=2; } if(n==3) sum+=speed[0]+speed[1]+speed[2]; if(n==2) sum+=speed[1]; if(n==1) sum+=speed[0]; cout<<sum<<endl; return 0; }
6.区间覆盖问题
把问题转化为区间问题,找到可以覆盖小岛的一个范围区间
局部最优解:依照左端带从小到大排序,查看下一个区间的情况:相交(point[i].x1>s的左端点&&point[i].x2>s),包含(point[i].x2<s),不相交也不包含(point[i].x1>s)从而分类讨论。
#include<bits/stdc++.h> using namespace std; int n,d; int x,y; double t; struct node { double x1,x2; }point[1000]; bool cmp(struct node a1,struct node a2) { return a1.x1<a2.x1; } int main() { while(cin>>n>>d) { if(n==0&&d==0) break; int num=1; for(int i=0;i<n;i++) { cin>>x>>y; if(y>d) { num=-1; break; } t=sqrt(d*d-y*y); point[i].x1=x-t; point[i].x2=x+t; } if(num!=-1) { sort(point,point+n,cmp); double s=point[0].x2; for(int i=1;i<n;i++) { if(s>point[i].x2) { s=point[i].x2; } if(s<point[i].x1) { num++; s=point[i].x2; } } } cout<<num<<endl; } }
简单的对以前在word中的算法笔记进行整理,自用,参考标注不完整,侵删