贪心
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
贪心的三个小栗子
一、分别有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(亿元)。
注意:销售时允许取出一部分库存。样例给出的情形是这样的:假如有三种月饼,其库存量分别为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的堆上取的纸牌,只能移到编号为N−1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。
例如N=4,4堆纸牌数分别为:
①9②8③17④6
移动3次可达到目的:
从 ③ 取4张牌放到④(9 8 13 10)->从③取3张牌放到 ②(9 11 10 10)-> 从②取1张牌放到①(10 10 10 10)。
输入格式
两行
第一行为:N(N 堆纸牌1001≤N≤100)
第二行为:A1,A2,…,An (NN堆纸牌,每堆纸牌初始数, 100001≤Ai≤10000)
输出格式
一行:即所有堆均达到相等时的最少移动次数。
输入样例
49 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、移至下一组
补题不香吗

浙公网安备 33010602011771号