zoukankan      html  css  js  c++  java
  • 初识贪心

    一、简单贪心

    贪心法是求解一类最优问题的方法,它总是考虑当前状态下局部最优(或较优)的策略,来使全局的结果达到最优或者较优。

    如果在想到某个似乎可行的策略,并且自己无法举出反例,那么就勇敢的去实现它。

    输入格式
    每个输入包含1个测试用例。每个测试用例先给出个不超过 1000 的正整数N表示月
    饼的种类数以及不超过500 (以万吨为单位)的正整数D表示市场最大需求量,随后一行给
    出N个正数表示每种月饼的库存量(以万成为单位),最后行给出N个正数表示每种月饼
    的总售价(以亿元为单位)。数字间以空格分隔。
    输出格式
    对每组测试用例,在行中输出最大收益,以亿元为单位并精确到小数点后两位。
    输入样例
    3 20
    18 15 10
    75 72 45
    输出样例
    94.50
    题意
    现有月饼需求量为D,已知n种月饼各自的库存量和总售价,问如何销售这些月饼,使
    得可以获得的收益最大。求最大收益。
    思路
    步骤1:这里采用“总是选择单价最高的月饼出售,可以获得最大的利润”的策略。
    因此,对每种月饼,都根据其库存量和总售价来计算出该种月饼的单价。
    之后,将所有月饼按单价从高到低排序。
    步骤2:从单价高的月饼开始枚举。
    ①如果该种月饼的库存量不足以填补所有需求量,则将该种月饼全部卖出,此时需求量
    减少该种月饼的库存量大小,收益值增加该种月饼的总售价大小。
    ②如果该种月饼的库存量足够供应需求量,则只提供需求量大小的月饼,此时收益值增
    加当前需求量乘以该种月饼的单价,而需求量减为0。
    这样,最后得到的收益值即为所求的最大收益值。
    策略正确性的证明:假设有两种单价不同的月饼,其单价分别为a和b (a<b)。如果当
    前需求量为K,那么两种月饼的总收入分别为aK与bK,而aK < bK显然成立,因此需要出
    售单价更高的月饼。
    注意点
    ①月饼库存量和总售价可以是浮点数(题目中只说是正数,没说是正整数),需要用
    double型存储。对于,总需求量D虽然题目说是正整数,但是为了后面计算方便,也需要定
    义为浮点型。很多得到“答案错误”的代码都错在这里。
    2当月饼库存量高于需求量时,不能先令需求量为0,然后再计算收益,这会导致该步收益为0,

    3.当月饼库存量高于需求量时,要记得将循环中断,否则出错。

    参考代码:

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 
     5 struct mooncake{
     6     double store; //库存量
     7     double sell; //总售价
     8     double price; //单价 
     9 }cake[1010];
    10 
    11 bool cmp(mooncake a,mooncake b)
    12 {
    13     //按单价从高到低排序
    14     return a.price>b.price; 
    15 }
    16 
    17 int main()
    18 {
    19     int n,D;  //月饼种类数和市场需求量
    20     cin >> n >> D;
    21     for(int i=0;i<n;i++)  //输入每种月饼的库存量 
    22     {
    23         cin >> cake[i].store;
    24      } 
    25      for(int j=0;j<n;j++)  //输入每种月饼的总售价并计算单价
    26      {
    27          cin >> cake[j].sell;
    28          cake[j].price=cake[j].sell/cake[j].store;
    29       } 
    30       sort(cake,cake+n,cmp); //单价从高到低排序
    31       double w = 0; //收益
    32        for(int i=0;i<n;i++)
    33        {
    34            if(cake[i].store <= D)  //如果需求量高于库存量
    35            {
    36                D -= cake[i].store;  //第i种月饼全部卖出
    37                w += cake[i].sell; 
    38             } 
    39             else  //库存量高于需求量 
    40             {
    41                 w += cake[i].price * D; //卖出剩余需求量的月饼
    42                 break; 
    43             }
    44         } 
    45         printf("%.2f
    ",w);
    46     return 0;
    47 }

    [PAT B1023]组个最小数

    题目描述
    给定数字0-9各若干个。可以任意顺序排列这些数字,但必须全部使用。目标是使得最
    后得到的数尽可能小(注意: 0不能做首位)。例如,给定两个0、 两个1、三个5和一个8,
    得到的最小的数就是10015558.
    现给定数字,请编写程序输出能够组成的最小的数。
    输入格式
    每个输入包含1个测试用例。每个测试用例在一行中给出 十个非负整数,顺序表示所相
    有数字0、数字....数字9的个数。整数间用一个空格分隔。 十个数字的总个数不超过50.
    且至少拥有一个非0的数字。
    输出格式
    在一行中输出能够组成的最小的数。
    输入样例
    2200030010
    输出样例
    10015558
    思路
    策略是:先从1~9中选择个数不为0的最小的数输出,然后从0~ 9输出数字,每个数
    字输出次数为其剩余个数。
    以样例为例,最高位为个数不为0的最小的数1,此后1的剩余个数减1 (由2变为1)。
    接着按剩余次数(0剩余两个,1剩余一个,5出现三个,8出现一个)依次输出所有数。
    策略正确性的证明:首先,由于所有数字都必须参与组合,因此最后结果的位数是确定
    的。然后,由于最高位不能为0,因此需要从[1,9]中选择最小的数输出(如果存在两个长度
    相同的数的最高位不同,那么定是最高位小的数更小)。 最后,针对除最高 位外的所有位,
    也是从高位到低位优先选择[0, 9]中还存在的最小的数输出。
    注意点
    由于第一位不能是0, 因此第一个数字必须从 1 ~ 9中选择最小的存在的数字,且找到这
    样的数字之后要及时中断循环。
    参考代码

     1 #include<iostream>
     2 using namespace std;
     3 int main()
     4 {
     5     int count[10]; //记录十个数字
     6     for(int i=0;i<10;i++)
     7     {
     8         cin >> count[i];
     9      } 
    10      for(int i=1;i<10;i++)  //从1~9种选择count不为0的最小数字 
    11      {
    12          if(count[i] > 0)
    13          {
    14              cout << i;
    15              count[i]--;
    16              break; //找到一个后就中断 
    17          }
    18      }
    19      for(int i=0;i<10;i++)
    20      {
    21          for(int j = 0;j < count[i]; j++)
    22          cout << i;
    23      }
    24      cout << endl;
    25     return 0;
    26 }

     二、区间贪心

    区间不相交问题

    给出N个开区间(x,y),从中选择尽可能多的开区间,使得这些开区间两两没有交集;

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn = 110;
     5 struct Interval{
     6     int x,y; //开区间左右端点 
     7 }I[maxn];
     8 bool cmp(Interval a,Interval b)
     9 {
    10     if(a.x != b.x)
    11     return a.x > b.x;
    12     else
    13     return a.y < b.y;
    14 }
    15 
    16 int main()
    17 {
    18     int n;
    19     while(cin >> n)
    20     {
    21         for(int i = 0;i < n; i++)
    22         cin >> I[i].x >> I[i].y;
    23         sort(I,I+n,cmp); //把区间排序
    24         //ans记录不想交区间个数,lastX记录上一个被选中区间的左端点
    25         int ans = 1;
    26         int lastX = I[0].x;
    27         for(int i = 1;i < n;i++)
    28         {
    29             if(I[i].y <= lastX)
    30             {
    31                 lastX = I[i].x;
    32                 ans ++;
    33             }
    34          } 
    35          cout << ans << endl;
    36     }
    37     return 0;
    38 }
  • 相关阅读:
    利用JBoss漏洞拿webshell方法
    jboss漏洞导致服务器中毒
    dubbo bug之 Please check registry access list (whitelist/blacklist)的分析与解决
    将list转为json字符串
    MySQL语句给字段值加1
    java int怎么转换为string
    HttpURLConnection如何添加请求头?
    eclipse下载egit插件,实现代码git同步问题
    eclipse编译项目用maven编译问题
    fastjson将java list转为json字符串
  • 原文地址:https://www.cnblogs.com/wlyperfect/p/12526905.html
Copyright © 2011-2022 走看看