zoukankan      html  css  js  c++  java
  • 贪心水题题解

    这里是三道贪心的水题。


    营养膳食

    题目描述

        阿月正在女朋友宁宁的监督下完成自己的增肥计划。
        为了增肥,阿月希望吃到更多的脂肪。然而也不能只吃高脂肪食品,那样的话就会导致缺少其他营养。阿月通过研究发现:真正的营养膳食规定某类食品不宜一次性吃超过若干份。
        比如就一顿饭来说,肉类不宜吃超过 1 份,鱼类不宜吃超过 1 份,蛋类不宜吃超过 1 份,蔬菜类不宜吃超过 2 份。阿月想要在营养膳食的情况下吃到更多的脂肪,当然阿月的食量也是有限的。 
        输入
        输入第一行包含三个正整数 n(n≤200),m(m≤100)和k(k≤100)。表示阿月每顿饭最多可以吃 m 份食品,同时有 n 种食品供阿月选择,而这 n 种食品分为 k 类。
        第二行包含 k 个不超过 10 的正整数,表示可以吃 1 到 k 类食品的最大份数。接下来 n 行每行包括 2 个正整数,分别表示该食品的脂肪指数 ai 和所属的类别 bi,其中 ai≤100,bi≤k。 
        输出
        输出一个数字即阿月可以吃到的最大脂肪指数和。
    

    样例输入

        6 6 3
        3 3 2
        15 1
        15 2
        10 2
        15 2
        10 2
        5 3
    

    样例输出

        60
    

    解析:

        贪心的题总会出现“更多”,“最多”等字眼(不过好像每道题都是这样)。在大概读完题之后,如果觉得能用贪心解决,那就想一个贪心。如果能举出反例,就再想一个贪心方法,如果最后反数据多得让你发现这道题不能再用贪心了,那正解可能是dp什么的。其实考试题不能轻易出贪心的,即使是贪心题也是得让你看不出来他是贪心,或者贪心的方法特别难。
        本道题的最优解是:按脂肪排序。每次吃脂肪最多的食物,如果当前食物的种类已经吃到上限了,那就不吃这个食物。
    

    代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,k;
    int lim[105];
    int ans;
    struct food
    {
        int fat;
        int kk;    
    };
    bool cmp(food a,food b)
    {
        return a.fat > b.fat;
    }
    food num[205];
    int main()
    {
    //    freopen("diet.in","r",stdin);
    //    freopen("diet.out","w",stdout);
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=k;i++)
            scanf("%d",&lim[i]);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&num[i].fat,&num[i].kk);
    
        sort(num+1,num+n+1,cmp);
    
        for(int i=1;i<=m;i++)
        {    
            if(lim[num[i].kk] > 0)
            {
                ans += num[i].fat;
                lim[num[i].kk] -= 1;
            }
        }
        printf("%d",ans);
        return 0;
    }

    整数区间

    题目描述

        一个整数区间[A,B]
        请编程完成以下任务:
        1.从文件中读取区间的个数及其它们的描述;
        2.找到满足下述条件的所含元素个数最少的集合中元素的个数,对于每一个区间,都至少
        有两个不同的整数属于该集合。 
    

    输入

        首行包括区间的数目 n,1<=n<=10000,接下来的 n 行,每行包括两个整数 a,b,被一空格隔开,0<=a<=b<=10000,它们是某一个区间的开始值和结束值。 
    

    输出

        第一行集合元素的个数,对于每一个区间都至少有两个不同的整数属于该区间,且集合所包含元素数目最少。 
    

    输入

        4
        3 6
        2 4
        0 2
        4 7
    

    输出

        4
    

    解释一下:

    可能题面描述的不太好,我解释一下。就是找一些最少的数,使每个区间至少包含这些数中的两个数,输出数的个数。
    

    我的代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int cc[10005];
    int ans,gg;
    bool cmp(int a,int b)
    {
        return a>b;
    }
    int main()
    {
    //    freopen("a.in","r",stdin);
    //    freopen("a.out","w",stdout);
        int l,r,n,mini=0x7fffffff,maxi=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&l,&r);
            for(int j=l;j<=r;j++)
            {
                cc[j]++;
            }
            mini = min(l,mini);
            maxi = max(r,maxi);
        }
        sort(cc+mini,cc+maxi,cmp);
        for(int i=mini;i<=maxi;i++)
        {
            ans += cc[i];
            gg++;
            if(ans >= 2*n)
                break;
        }
        printf("%d",gg);
        return 0;
    }
    /*
    4
    3 6
    2 4
    0 2
    4 7
    */

    解析:

        要不怎么说这道题数据水。我的方法绝对有瑕疵。
          我是这么干的。取1到10000这个区间(整形数组,1~10000是下标)。每读入一个区间,就把它覆盖上(就是这个数组每个下标存的数+1),这样把这些区间捏到一起,再将这个覆盖后的数组降序排序,然后从大到小一直累加加加,一直加到比区间个数n的二倍大,输出累加的这些数的个数。
        这个方法太土了,我都不知道怎么证他是对的这道题就a了。所以一定是数据太水了。我给一个正解代码吧。
    

    正解代码:

    #include<iostream>  
    #include<algorithm>   
    using namespace std;  
    struct node  
    {  
        int l;  
        int r;  
    }a[10001];  
    bool cmp(node a,node b)  
    {  
        return (a.r<b.r||a.r==b.r&&a.l<b.l);  
    }  
    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,cmp);  
        int q[10001],front=2,back=1; 
        q[1]=a[1].r-1;q[2]=a[1].r; 
        for(int i=2;i<=n;i++)  
        { 
            int k=back; 
            while(a[i].l>q[back]&&back<k+2) 
              back++;
    
            if(back==k+1) q[++front]=a[i].r;  
            if(back==k+2) q[++front]=a[i].r-1,q[++front]=a[i].r;  
    
        } 
        cout<<front; 
    }   
    #include <stdio.h>
    
    #define maxN 10005//最大边条数
    #define inf 0x7fffffff//最大距离
    
    struct Edge 
    {
        int v, w, next;
    }edge[4 * maxN];//边集
    
    int dis[maxN];
    bool vis[maxN];
    int queue[maxN];
    int preEdge[maxN];//同一个顶点的前一条边
    
    int edgeNum,n,maxn;
    
    void addEdge(int u, int v, int w)//添加一条边
    {
        edge[edgeNum].v = v;
        edge[edgeNum].w = w;
        edge[edgeNum].next = preEdge[u];
        preEdge[u] = edgeNum ++;
    }
    
    void spfa()//spaf算法
    {
        int head = 0, tail = 1;
        for (int i = 0; i <= maxn; ++ i)
        {
            dis[i] = -inf;
        }
        queue[head] = 0;
        dis[0] = 0;
        while (head != tail)
        {
            int u = queue[head];
            vis[u] = true;
            for (int p = preEdge[u]; p != 0; p = edge[p].next)
            {
                int v = edge[p].v;
                if (dis[v] < dis[u] + edge[p].w)
                {
                    dis[v] = dis[u] + edge[p].w;
                    if (!vis[v])
                    {
                        vis[v] = true;
                        queue[tail] = v;
                        tail ++;
                        if (tail == maxN)
                        {
                            tail = 0;
                        }
                    }
                }
            }
            vis[u] = false;
            head ++;
            if (head == maxN)
            {
                head = 0;
            }
        }
    }
    
    int main()
    {
        scanf("%d", &n);
        edgeNum = 1;
        maxn = 0;
        while (n --)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            if (v + 1 > maxn)
            {
                maxn = v + 1;
            }
            addEdge(u, v + 1, 2);
        }
        for (int i = 0; i <= maxn; ++ i)
        {
            addEdge(i, i + 1, 0);
            addEdge(i + 1, i, -1);
        }
        spfa();
        printf("%d
    ", dis[maxn]);
        return 0;
    View Code

    运输

    题目描述

        现在已知 N 件商品,和搬运它们其中每一件的费用。现在搬家公司老板 Mr.sb 决定让我们每次任意选取 2 件商品。然后这 2 件商品只算一件商品的费用。但是这个商品的搬运费用是将选出的 2 个商品的费用之和除以 k 的运算结果。如此反复。直到只收一件商品的钱。这个就是商店要付的费用。掌柜的想尽可能的少付钱,以便将更多的钱捐给希望工程。所以请你帮他计算一下最少只用付多少钱。 
    

    输入

        n,k
        w1,w2,...,wn(每一件商品的搬运费用)
        n,k<=10000
    

    输出

        最少付多少钱
    

    样例输入

        5 2
        1 2 3 4 5
    

    样例输出

        1
    

    解析:

        贪心策略就是取两个最大的数,除完k放回去,再取两个最大的,再放回去……因为贪心总是什么取最大啦,排序啦这个样子。用优先队列就比较方便。
    

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    typedef long long ll;
    using namespace std;
    int n,k,hop;
    priority_queue <int> q;
    int main()
    {
    //    freopen("trans.in","r",stdin);
    //    freopen("trans.out","w",stdout);
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&hop);
            q.push(hop);
        }
        while(n>1)
        {
            hop = q.top();
            q.pop();
            hop += q.top();
            q.pop();
            hop /= k;
            q.push(hop);
            n--;
        }
        printf("%d",hop);
        return 0;
    }
  • 相关阅读:
    linux 运维
    mariadb replication
    phpmyadmin
    Objective-C设计模式——单例Singleton(对象创建)
    收藏iOS学习资料
    axios拦截器
    vue单页面优化
    html设置http缓存代码
    js数组去重,排序的几种方法
    前端移动端问题
  • 原文地址:https://www.cnblogs.com/Ch-someone/p/8593264.html
Copyright © 2011-2022 走看看