2.26网课笔记(贪心)

1.贪心算法是什么?

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解。 贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择。也就是说,不从整体最优上加以考虑,做出的只是在某种意义上的局部最优解。

2.贪心算法经典题(我认为的)

2.1. 月饼

又到了我最喜欢的那道题:

PTA1020月饼
根据题意,我们可以很直接得得知这道题应该使用贪心算法,即每次都选择先出售掉价值最高的月饼(因为月饼的需求总量是不变的,不会因为我们卖了贵月饼就少要一点......)
思路就是:算出每种月饼的单价,然后把单价最高的优先卖出去,同时需求量要减去每种月饼的数量,如果需求小于该类月饼的库存,则用单价去×剩下的需求量

c++代码如下:
 

#include <bits/stdc++.h>
using namespace std;

struct mooncake
{
    double store;
    double sell;
    double price;
} cake[1005];

bool cmp(mooncake a, mooncake b)
{
    return a.price > b.price;
}

int main()
{

    int n, d;
    double ans = 0;
    cin >> n >> d;

    for (int i = 0; i < n; i++)
    {
        cin >> cake[i].store;
    }
    for (int i = 0; i < n; i++)
    {
        cin >> cake[i].sell;
        cake[i].price = cake[i].sell / cake[i].store;
    }

    sort(cake, cake + n, cmp);

    for (int i = 0; i < n; i++)
    {
        if (cake[i].store <= d)
        {
            d -= cake[i].store;
            ans += cake[i].sell;
        }
        else
        {
            ans += cake[i].price * d;
            break;
        }
    }

    printf("%.2f", ans);
    return 0;
}

2.2.石头堆

先看题!
P1090合并果子

依然是很简单的贪心,我们每次都选择最小的两组石头来进行合并。首先写入数据,然后把排一次序
随后,我们每次都操作这个列表的前两项,ans累加所需的力气,然后再把第一位和第二位进行合并,将其插入到合理的位置。切记!不能每次操作后都对数组进行一次sort排序(必超时)
c++代码

 #include <bits/stdc++.h>
 using namespace std;
 ​
 int n, ans;
 int arr[100000];
 int main()
 {
     cin >> n;
     for (int i = 0; i < n; i++)
     {
         cin >> arr[i];
     }
     sort(arr, arr + n);
     for (int i = 0; i <= n-2; i++)
     {
         ans += (arr[i] + arr[i + 1]);
         arr[i + 1] += arr[i];
         for (int j = i+1 ; j <= n-2; j++)
         {
             if(arr[j] > arr[j + 1])
                 swap(arr[j], arr[j + 1]);
             else
                 break;
         }
     }
     cout << ans;
     return 0;
 }

 

当然,我们有更优雅的STL库方法来实现(这道题完美的契合了它!)

优先队列

每次都选择两个最小的来合并,然后把合并好的添加进原有的序列中,并且无论怎样每次都是选择两个最小的,我打开这道题一看,满篇都写着"优先队列"

c++代码如下:

 #include <bits/stdc++.h>
 using namespace std;
 //优先队列方法~
 ​
 priority_queue<int, vector<int>, greater<int>> q; //升序,从小到大
 //priority_queue<int, vector<int>, less<int> > q;    //降序,从大到小
 ​
 int n, temp, ans;
 int main()
 {
 ​
     cin >> n;
     for (int i = 0; i < n; i++)
     {
         cin >> temp;
         q.push(temp);
     }
     while (q.size() >= 2)
     {
         int a = q.top();
         q.pop();
         int b = q.top();
         q.pop();
         ans += (a + b);
         q.push(a + b);
     }
 ​
     cout << ans;
 ​
     return 0;
 }

 

2.3 排列出的最小数

看题!

PTA B1023 组个最小数

策略很简单:先从1-9中选择一个最小的数输出(因为0不能开头) ,然后从0-9输出数字,每个数字输出次数为其剩余个数(贪心)
证明正确性:首先,由于所有的数字都必须参与组合,因此最后结果的位数是确定的。然后,由于最高位不能为0,所有从除0外的最小数来输出(如果存在两个长度相同的数的最高位不相同,那么一定是最高位小的数更小。)最后,针对除最高位外的所有位,也是从高位到低位优先选择[0,9]中还存在的最小的数输出
这道题很简单,大家现在的水平足矣做出来。
c++代码如下:

 #include <bits/stdc++.h>
 using namespace std;
 int a[15], temp;
 ​
 int main()
 {
     for (int i = 0; i <= 9; i++)
     {
         cin >> a[i];
     }
 ​
     for (int i = 1; i <= 9; i++)
     {
         if (a[i] != 0)
         {
             temp = i;
             cout << i;
             a[i]--;
             break;
         }
     }
 ​
     while (a[0]--)
         cout << '0';
 ​
     for (int i = temp; i <= 9; i++)
     {
         while (a[i]--)
             cout << i;
     }
 ​
     return 0;
 }

 

2.4 买卖股票系列第一题

题目:121. 买卖股票的最佳时机

思路:最小的时候买进,最大的时候卖出。仔细讲讲实现

java代码:
 

 class Solution {
     public int maxProfit(int[] prices) {
         int max=0,min;
         if(prices.length <= 1) return 0;
         min = prices[0];
         for(int i = 1; i < prices.length;i++){
             if(prices[i] < min){
                 min = prices[i];
             }else{
                 max = prices[i] - min > max?prices[i]-min : max;
             }
         }
         return max;
     }
 }

 

c++:
 

 class Solution {
 public:
     int maxProfit(vector<int>& prices) {
         if(prices.size() <= 1) return 0;
         int min1 = prices[0],max1;
         for(int i = 1;i < prices.size();i++){
             if(prices[i] < min1){
                 min1 = prices[i];
             }else{
                 max1 = prices[i] - min1 > max1 ? prices[i] - min1: max1;
             }
         }
         return max1;
     }
 };

 

2.5皮一下很开心

依然是122. 买卖股票的最佳时机 II

思路:畅所欲言。大家一起讨论~~

 

3.什么时候用贪心?

贪心最重要的特点:

当你的选择对后续的选择不产生影响的时候,就贪心

这种情况就不能用!

https://www.cherryg.cn/detail/3

//经典入门DP问题:01背包

posted @ 2021-03-03 14:43  樱丨雅诗兰黛  阅读(121)  评论(0)    收藏  举报
Live2D