初识贪心

一、简单贪心

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

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

输入格式
每个输入包含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\n",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 }

 

posted @ 2020-03-19 20:22  树下一朵云  阅读(176)  评论(0编辑  收藏  举报