zoukankan      html  css  js  c++  java
  • 2017级算法模拟上机准备篇(贪心 初阶)

    贪心问题的关键在于选择合适的贪心策略(局部最优解可以推导出全局最优解

    简单·简单的贪心

    在黑板上写了N个正整数做成的一个数列,进行如下操作:

    每一次擦去其中的两个数a和b,然后在数列中加入一个数a×b+1,如此下去直至黑板上剩下一个数。

    在所有按这种操作方式最后得到的数中,最大的max,最小的为min,则该数列的极差定义为M=max-min。

    这道题是用优先队列辅助实现贪心问题的一道典型题。

    贪心和优先队列为什么能有不解之缘? 其实仔细思考一下就会明白

    开两个优先队列,每次取最小的两个操作一下把结果放进去,最后剩下就是max。每次取最大的两个操作一下把结果放进去,最后剩下的就是min。

    什么?你要我证明。

    那就来好了。

    假设经(N-3)次变换后得到3个数:a,b,max’(max’≥a≥b),其中max’是(N-2)个数经(N-3)次变换后所得的最大值,此时有两种求值方式,设其所求值分别为x、y 则有:x=(a×b+1)×max’+1,y=(a×max’+1)×b+1。所以x-y=max’-b≥0若经(N-2)次变换后所得的3个数为:b(m≥a≥b)且m不为(N-2)次变换后的最大值,即m<max’则此时所求得的最大值为:=(a×b+1)×m+1 此时 - =(1+ab)(max’-m)>0 所以此时不为最优解。

    所以若使第k(1≤k≤N-1)次变换后所得值最大,必使(k-1)次变换后所得值最大(符合贪心策略的特点2),在进行第k次变换时,只需取在进行(k-1)次变换后所得数列中的两最小数p,q施加f操作:p←p×q+1,q←∞即可,因此此题可用贪心策略求解。讨论完毕。
    在求min时,我们只需在每次变换的数列中找到两个最大数p,q进行变换:p←p×q+1,q←-∞即可。原理同上。

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int maxlen=25;
    int ar[maxlen];
    int main(){
        
        int n,i,j,k,num1,num2,num3,min,max;
        while(~scanf("%d",&n)){
            priority_queue< int,vector<int>,greater<int> > p;
            priority_queue< int,vector<int>,less<int> > q;
            while(p.empty() == false)
                    p.pop();
            while(q.empty() == false)
                    q.pop();
            for(i=1;i<=n;i++){
                scanf("%d",&ar[i]);
                p.push(ar[i]);
                q.push(ar[i]);
            }
            while(p.size() >=2){
                num1=p.top();
                p.pop();
                num2=p.top();
                p.pop();
                p.push(num1 * num2 + 1);
            }
            max=p.top();
            while(q.size() >=2){
                num1=q.top();
                q.pop();
                num2=q.top();
                q.pop();
                q.push(num1 * num2 + 1);
            }
            min=q.top();
            printf("%d
    ",max-min);
        }
        
        return 0;
    }

    AlvinZH的学霸养成记II 

    这道题,其实也是一道贪心+sort+优先队列的题。

    我们可以设置一个curtime来作为一个扫描的指针,对于每门课程,如果可以学习的话( curtime + last_time) <= ddl 那么就学习,否则的话,就用之前的最长时间的课程替换掉?为什么要替换其实就体现了贪心的思想,在同样的课程含量下,curtime越小那么。我们选择的余地就会越大。(局部最优解推导出全局最优解)

    #include <iostream>
    #include <algorithm>
    #include <string.h>
    #include <queue>
    using namespace std;
    
    typedef struct mooc{
        int d;
        int e;
    }course;
    //优先队列的使用
    const int Maxlen=1e5 + 10;
    course ar[Maxlen];
    bool cmp(course a,course b){
        return a.e < b.e;
    }
    int main(){
        
        int i,j,k,n,cur,ans;
        while(~scanf("%d",&n)){
            for(i=0;i<n;i++)
                scanf("%d %d",&ar[i].d,&ar[i].e);
            sort(ar,ar+n,cmp);
            cur=0;
            ans=0;
            priority_queue<int> q;
            for(i=0;i<n;i++){
                cur+=ar[i].d;
                q.push(ar[i].d);
                
                if(cur>ar[i].e){
                    cur-=q.top();
                    q.pop();
                }
                else ans++;
            }
            printf("%d
    ",q.size());    
        }
        
        return 0;
    }

    挑战神奇宝贝联盟

    贪心+优先队列辅助实现

    毒素多的应该尽早解决,故使用优先队列模拟即可。

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int maxlen=1e5 + 10;
    int ar[maxlen];
    int main(){
        
        int n,i,j,k,t,num,temp;
        while(~scanf("%d",&n)){
            priority_queue< int,vector<int> ,less<int> >  q;
            for(i=1;i<=n;i++){
                scanf("%d",&ar[i]);
                q.push(ar[i]);
            }
            scanf("%d",&k);
            t=0;
            while(q.size() > 0){
                num=q.top();
                q.pop();
                num-=k;
                j=0;
                while(q.size() > 0){
                    temp=q.top();
                    q.pop();
                    temp-=1;
                    ar[++j]=temp;
                }
                for(i=1;i<=j;i++)
                    if(ar[i]>0)
                        q.push(ar[i]);
                if(num>0)
                q.push(num);
                
                t++;
            }
            printf("%d
    ",t);
        }
        return 0;
    }

     

  • 相关阅读:
    5. 字符串提取
    4.字符串连接
    3. 忽略大小写的字符串比较
    2.Calendar类的使用
    1.==和equals()
    50.使用DOM4J解析XML文件
    C# json提取多层嵌套到数组
    打开SDK Manager检查Android SDK下载和更新失败的解决方法
    (微信API接口开发) 使用HttpWebRequest进行请求时发生错误:基础连接已关闭,发送时发生错误处理
    javascript里面的数组,json对象,动态添加,修改,删除示例
  • 原文地址:https://www.cnblogs.com/visper/p/10120095.html
Copyright © 2011-2022 走看看