贪心
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。
也就是说,我们要对于一个大的问题分解为一个一个可以用同一个最值策略(贪心策略)进行求解的问题
对于一个给定的问题,往往可能有好几种量度标准。初看起来,这些量度标准似乎都是可取的,但实际上,用其中的大多数量度标准作贪婪处理所得到该量度意义下的最优解并不是问题的最优解,而是次优解。因此,选择能产生问题最优解的最优量度标准是使用贪婪算法的核心。
贪婪算法可解决的问题通常大部分都有如下的特性(看着还可以):
⑴ 有一个以最优方式来解决的问题。为了构造问题的解决方案,有一个候选的对象的集合。
⑵ 随着算法的进行,将积累起其它两个集合:一个包含已经被考虑过并被选出的候选对象,另一个包含已经被考虑过但被丢弃的候选对象。
⑶ 有一个函数来检查一个候选对象的集合是否提供了问题的解答。该函数不考虑此时的解决方法是否最优。
⑷ 还有一个函数检查是否一个候选对象的集合是可行的,也即是否可能往该集合上添加更多的候选对象以获得一个解。和上一个函数一样,此时不考虑解决方法的最优性。
⑸ 选择函数可以指出哪一个剩余的候选对象最有希望构成问题的解。
⑹ 最后,目标函数给出解的值。
最经典的贪心思想的算法就属于前面所讲到的prim和kruscal了
这里有几个例题,可以供大家了解(都是一本通上的例题):
1422:【例题1】活动安排
#includeusing namespace std; struct node { int st,ed; }a[1001]; bool cmp(node x,node y) { return x.ed<y.ed; } int main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i].st>>a[i].ed; } sort(a+1,a+n+1,cmp); int t=a[1].ed; int ans=1; for(int i=2;i<=n;i++) { if(a[i].st>=t) { ans++; t=a[i].ed; } } cout<<ans; return 0; }
1423:【例题2】种树
#includeusing namespace std; struct node { int s,e,v; int mid; }a[5001]; int n,m; bool used[30005]; bool cmp(const node &x,const node &y) { return x.e<y.e; } inline void init() { cin>>n>>m; for(int i=1;i<=m;i++) { cin>>a[i].s>>a[i].e>>a[i].v; } sort(a+1,a+m+1,cmp); } inline void solve() { int k,ans=0; for(int i=1;i<=m;i++) { k=0; for(int j=a[i].s;j<=a[i].e;j++) { if(used[j]) { k++; } } if(k>=a[i].v) { continue; } for(int j=a[i].e;j>=a[i].s;j--) { if(!used[j]) { used[j]=1; k++; ans++; if(k==a[i].v) { break; } } } } cout<<ans; } int main() { init(); solve(); return 0; }
1424:【例题3】喷水装置(AC代码的无解应该是cout<<0;)
#includeusing namespace std; int n,cnt,L,h,x,r; struct node { double x,y; }a[15001]; bool cmp(const node &x,const node &y) { return x.x<y.x; } inline void Read() { cin>>n>>L>>h; cnt=0; for(int i=1;i<=n;i++) { cin>>x>>r; if(r<=h/2) continue; cnt++; a[cnt].x=x-sqrt(r*r-h*h/4.0); a[cnt].y=x+sqrt(r*r-h*h/4.0); } sort(a+1,a+1+cnt,cmp); } inline void solve() { double t=0; int ans=0,bj=1,i=1; while(t //顺序扫描 { ans++; double s=t; for(;a[i].x<=s&&i<=cnt;i++)//依次找到覆盖l的最大右端 if(ta[i].y; if(t==s&&s //无解判断 { cout<<0<<endl; bj=0; break; } } if(bj) cout< endl; } inline void clean() { memset(a,0,sizeof(a)); } int main() { int T; cin>>T; while(T--) { Read(); solve(); clean(); } return 0; }
1425:【例题4】加工生产调度
#include#include #include #include using namespace std; const int N = 10001; int ans[N], a[N], b[N], m[N], s[N]; int n; int main(){ scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &a[i]); for(int i=1; i<=n; i++) scanf("%d", &b[i]); for(int i=1; i<=n; i++){ m[i] = min(a[i], b[i]); s[i] = i; } for(int i=1;i<=n-1; i++) for(int j=i+1; j<=n; j++) if(m[i] > m[j]){ swap(m[i], m[j]); swap(s[i], s[j]); } int k=0, t=n+1; for(int i=1; i<=n; i++) if(m[i] == a[s[i]]){ k++; ans[k] = s[i]; }else{ t--; ans[t] = s[i]; } k = 0, t = 0; for(int i=1; i<=n; i++){ k += a[ans[i]]; if(t < k) t = k; t += b[ans[i]]; } printf("%d\n", t); for(int i=1; i<=n; i++) printf("%d ", ans[i]); printf("\n"); return 0; }
1426:【例题5】智力大冲浪
#include#define _for(i,a,n) for(int i=a;i #define rep(i,a,n)for(int i=a;i<=n;++i) #define input() int t;cin>>t;while(t--) #define close() ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) using namespace std; typedef long long ll; typedef pair<int, int> P; const int maxn = 1e4; priority_queue<int, vector<int>, greater<int> > Q; P arr[maxn]; int main() { int n, m; cin >> m >> n; _for(i, 0, n) cin >> arr[i].first; _for(i, 0, n) cin >> arr[i].second; sort(arr, arr + n); _for(i, 0, n) { Q.push(arr[i].second); if(Q.size() > arr[i].first) { m -= Q.top(); Q.pop(); } } cout << m << endl; return 0; }