zoukankan      html  css  js  c++  java
  • 贪心小记

    贪心策略是一种在每次决策是采取当下意义下最优策略的算法。贪心算法,要满足由局部最优解可以推出全局最优解。简单来说,就是把一个很大的问题拆成一个个子问题,然后找出每个子问题的最优解,组合成全局最优解

    贪心问题总是只看眼前,并不考虑以后可能造成的影响 。因此在选择贪心算法时,一定要考虑它的正确性。

    举个不正确的贪心:noip2011提高组day2第3题观光公交,当年考试时的数据用贪心可以100pts(具体思路可以看题解),然鹅实际上贪心是错的,被别人卡掉了qwq;

    贪心的常见做法:

    在提高组难度以下的题目中,最常见的贪心有两种。一种是:「我们将 XXX 按照某某顺序排序,然后按某种顺序(例如从小到大)处理」。另一种是:「我们每次都取 XXX 中最大/小的东西,并更新 XXX」,有时「XXX 中最大/小的东西」可以优化,比如用优先队列维护。

    排序法:

    用排序法常见的情况是输入一个包含几个(一般一到两个)权值的数组,通过排序然后遍历模拟计算的方法求出最优值。

    后悔法:

    eg:洛谷p2949工作调度

    贪心思想:

          1 . 先假设每一项工作都做,将各项工作按截止时间排序后入队。

          2 . 在判断第 i 项工作做与不做时,若其截至时间符合条件,则将其与队中报酬最小的元素比较,若第 i 项工作报酬较高(后悔),则 ans+=a[i].p-q.top()。

           PS :用优先队列(小根堆)来维护队首元素最小。

    贪心问题说简单也简单,说难也难,主要在于证明想到的贪心是正确的。

    下面举几个贪心算法的经典应用:

    1.选择不相交区间问题:

    给定n个开区间(ai,bi),选择尽量多个区间,使得这些区间两两没有公共点。

    【思路】按照结束时间bi从小到大排序,依次考虑每个事件,如果不会重复,那么就可以选择这个事件。

    eg:活动安排

    将活动按结束时间排序,排序后从第一个扫到最后一个,如果与前面选到的不冲突就选择这个事件

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int n;
    
    struct node{
        int st,ed;
    }a[1005];
    
    bool cmp(node x,node y){
        return x.ed<y.ed;
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
          scanf("%d%d",&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<<endl;
    }

    2.区间选点问题:

    给定n个闭区间[ai,bi],在数轴上选尽量少的点,使得每个区间都至少有一个点(不同区间内含的点可以是同一个);

    【思路】按结束bi从小到大排序,对于区间,若没有点,则加一个点在队尾(因为队尾是最可能被重复覆盖的地方);

    eg:种树

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    
    using namespace std;
    
    int n,m,k,ans;
    bool p[50100];
    struct h{
        int b,e,t;
    }a[50100];
    
    bool cmp(h x,h y){
        return x.e<y.e;
    }
    
    int main(){
        
        cin>>n>>m;
        
        for(int i=1;i<=m;i++)
          cin>>a[i].b>>a[i].e>>a[i].t;
          
        sort(a+1,a+m+1,cmp);
        
        for(int i=1;i<=m;i++){
            k=0;
            for(int j=a[i].b;j<=a[i].e;j++)
              if(p[j]) k++;
            if(k>=a[i].t) continue;
            
            for(int j=a[i].e;j>=a[i].b;j--)
                if(!p[j]) {
                    p[j]=1;
                    k++;
                    ans++;
                    if(k==a[i].t) break;
            }
            
        }
        
        cout<<ans;
    }

    3.区间覆盖问题:

    之前讲过了qwq?就是引水入城的线段覆盖中的一种吧qwq

    eg:喷水装置

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int n,cnt,l,h,x,r;
    
    struct seg{double x,y;}a[20005];
    
    bool cmp(const seg &x,const seg &y){
        return x.x<y.x;
    }
    
    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);
        }
    }
    
    void solve(){
        double t=0;
        int ans=0,bj=1,i=1;
        while(t<l){
            ans++;
            double s=t;
            for(;a[i].x<=s&&i<=cnt;i++)
              if(t<a[i].y) t=a[i].y;
            if(t==s&&s<l) {
                cout<<"0"<<endl;
                bj=0;
                break;
            }
        }
        if(bj) cout<<ans<<endl;
    }
    
    int main(){
        int t;
        cin>>t;
        while(t--){
            read();
            sort(a+1,a+cnt+1,cmp);
            solve();
        }
    }
  • 相关阅读:
    软件工程14—第09组 Beta冲刺(2/4)
    软件工程13—第09组 Beta冲刺(1/4)
    软件工程12—第09组 Alpha事后诸葛
    软件工程11—第09组 Alpha冲刺(4/4)
    软件工程10—第09组 Alpha冲刺(3/4)
    软件工程09—第09组 Alpha冲刺(2/4)
    软件工程08—第09组 Alpha冲刺(1/4)
    软件工程07—第09组 团队Git现场编程实战
    软件工程06—亚瑟王の十三水2.0
    第06组 Alpha冲刺(4/6)
  • 原文地址:https://www.cnblogs.com/zhuier-xquan/p/10983451.html
Copyright © 2011-2022 走看看