贪心

 

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关
贪心的三个小栗子
 
一、分别有1,5,10,50,100元,分别有5,2,2,3,5张纸币。问若要支付k元,则需要多少张纸币?(因为贪心,所以要算最少的)
1、先从大到小排序
2、从大到小进行组合找出最少使用的张数
#include <iostream>
#include <algorithm>
using namespace std;
 
const int N=5;   
int Money[N]={5,2,2,3,5};  
int Value[N]={1,5,10,50,100};  
 
int solve(int money){
    int num=0;
    for(int i=N-1;i>0;i--){
        //c为使用纸币的张数,在需要用面值为vaule[i]的张数和已有张数里选取最小的;
        int c=min(money/Value[i],Money[i]);
        money=money-Value[i]*c;        
        num+=c;
    }
    if(money>0){
        num=-1;        
    }
    return num;
}
int main(){
    int money;
    cin>>money;//输入一共需要支付多少钱
    int res=solve(money);
    if(res!=-1){
        cout<<res<<endl;
    }else{
        cout<<"no"<<endl;
    }
    return 0;
 
}

 

二、月饼问题

月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不用风味的月饼。现给定所有种类月饼的库存量,总售价以及市场的最大需求量,试计算可以获得的最大收益是多少。
注意:销售时允许取出一部分库存。样例给出的情形是这样的:假如有三种月饼,其库存量分别为18,15,10万吨,总售价分别为75,72,45亿元。如果市场的最大需求量只有20万吨,那么最大收益策略应该是卖出全部的15万吨第二种月饼以及5万吨第三种月饼,获得72+45/2=94.5(亿元)。

输入格式

每个输入包含1个测试用例。每个测试用例先给出一个不超过1000的正整数N表示月饼的种类数以及不超过500(以万吨为单位)的正整数D表示市场最大需求量;随后一行给出N个正数表示每种月饼的库存量(以万吨为单位);最后一行给出N个正数表示每种月饼的总售价(以亿元为单位)。数字间以空格分割。

输出格式

对每组测试用例,在一行中输出最大收益,以亿元为单位并精确到小数点后两位。

输入样例

3 20
18 15 10
75 72 45

输出样例

94.50


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

struct mooncake {
    double stock;
    double sales;
    double price;
}cakes[1010];

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

int main() {
    
    int n;
    double D;
    scanf("%d%lf", &n, &D);
    
    for(int i = 0; i < n; i++) {
        scanf("%lf", &cakes[i].stock);
    }
    for(int i = 0; i < n; i++) {
        scanf("%lf", &cakes[i].sales);
        cakes[i].price = cakes[i].sales / cakes[i].stock;//求单价(性价比)
    }
    
    sort(cakes, cakes + n, cmp);//从大到小进行排序
    double ans = 0;
    for(int i = 0; i < n; i++) {
        if(cakes[i].stock <= D) {
            D -= cakes[i].stock;//把小于需求且性价比大的放进去
            ans += cakes[i].sales;
        } else {
            ans += cakes[i].price * D;
            break;
        }
    }
    printf("%.2f\n", ans);
    
    return 0;
}

 

三、

N堆纸牌,编号分别为 1,2,…,N。每堆上有若干张,但纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌,然后移动。

移牌规则为:在编号为1堆上取的纸牌,只能移到编号为2的堆上;在编号为N的堆上取的纸牌,只能移到编号为N1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。

现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。

例如N=4,4堆纸牌数分别为:

9817④6

移动3次可达到目的:

从 ③ 取4张牌放到④(9 8 13 10)->从③取3张牌放到 ②(9 11 10 10)-> 从②取1张牌放到①(10 10 10 10)。

输入格式

两行

第一行为:NN 堆纸牌1001N100)

第二行为:A1,A2,,An (NN堆纸牌,每堆纸牌初始数, 100001Ai10000)

输出格式

一行:即所有堆均达到相等时的最少移动次数。

输入样例

4
9 8 17 6

输出样例

3

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,card[105],ave,step;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
scanf(
"%d",&card[i]),ave+=card[i]; ave=ave/n;//求平均数 for(int i=1;i<=n;++i) { if(ave==card[i]) continue; card[i+1]+=card[i]-ave,step++;//相当于对后一组进行操作,不论正负后面的数都会改变,一般这种题目都会得到想要的结果,所以算到最后一组一般都会成立 } printf("%d\n",step); return 0; }

1、求平均数

2、做差

3、移至下一组

posted @ 2020-02-13 21:02  MOSHANG_SUSIE  阅读(360)  评论(0)    收藏  举报