目录
贪心算法
贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。
贪心类问题是很常见的考点,贪心算法更重要的是一种贪心的思想,它追求的是当前最优解,从而得到全局最优解
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
举例说明
- 例子 1:地上有 3 张纸币,分别是 5 元、1 元和 10 元,问你只能拿一张,最多能拿多少钱?
解析:很明显,10 元。
- 例子 2:地上有 n 张纸币,有 1 元的,有 5 元的,还要 10 元的,问你只能拿一张,最多能拿 多少钱?
解析:很明显,还是 10 元。
- 例子 3:地上有很多纸币,有 a 张 1 元的,有 b 张 5 元的,还要 c 张 10 元的,问你从中拿 x 张,最多能拿多少钱?
解析:大家应该都能想到,肯定是优先拿 10 元的,如果 10 元的拿完了,再拿 5 元的,最后才 会拿 1 元的。这就是贪心的思想,所以贪心其实是很容易想到的。
- 例子 4:有 n 个整数构成的集合,现在从中拿出 x 个数来,问他们的和最大能是多少?
解析:相信大家都能想到,优先拿大的,从大到小一个个拿,这样组成的和最大。那么在解决这个问题之前,我们需要先排序,从大到小的排好序,然后将前 x 个数的和累加起来就是答案。
我们使用贪心的时候,往往需要先按照某个特性先排好序,也就是说贪心一般和 sort一起使用
喝饮料
题目描述
商店里有n中饮料,第i种饮料有mi毫升,价格为wi。
小明现在手里有x元,他想吃尽量多的饮料,于是向你寻求帮助,怎么样买才能吃的最多。
请注意,每一种饮料都可以只买一部分。
输入描述:
有多组测试数据。 第一行输入两个非负整数x和n。 接下来n行,每行输入两个整数,分别为mi和wi。 所有数据都不大于1000。 x和n都为-1时程序结束。
输出描述:
请输出小明最多能喝到多少毫升的饮料,结果保留三位小数。
输入样例#:
233 6 6 1 23 66 32 23 66 66 1 5 8 5 -1 -1
输出样例#:
136.000
- 小明想要喝尽量多的饮料的话,肯定优先选择性价比 最高的饮料喝,也就是说 1 毫升的价格最低的饮料先喝,那么我们就需要去比较,每种饮料 1 毫升的价格是多少。然后按照这个单价从低到高依次排序,然后一个一个往后喝,这样可以保 证小明能喝到最多的饮料
#include<stdio.h>
#include <bits/stdc++.h>//万能头文件
using namespace std;
struct node{
double w,m;
}p[1005];
bool cmp(node a,node b){
return a.w/a.m <b.w/b.m;//按照每毫升的价格从低到高排序
}
int main() {
int x ,n;
while(scanf("%d%d",&x,&n) != EOF){
if(x == -1 && n == -1) break;
for(int i = 1;i<=n;i++)
scanf("%lf%lf",&p[i].m,&p[i].w);
sort(p+1,p+1+n,cmp);
double ans = 0;
for(int i = 1;i<=n;i++){
if(x>p[i].w){//如果剩余的钱能全买
ans += p[i].m;
x-=p[i].w;
}
else{//如果剩余的钱买不完这种饮料
ans += (p[i].m * x/p[i].w);
break;//到这里x已经为0了
}
}
printf("%.3lf\n",ans);
}
return 0;
}
组队刷题
题目描述
某天,吴大佬准备和菜鸡Tirpitz一起组队刷题,聪明的吴大佬把题目分成了n个板块,每个板块有w[i]个题目,刷完这个板块需要消耗吴大佬m[i]的精力。吴大佬没有必要在一个板块死磕,/*毕竟有咸鱼队友Tirpitz*/。相反,如果他消耗m[i]%的精力时,他会解决这个专题w[i]%的题目,现在吴大佬想给聪明的你一个任务,让你计算吴大佬一共能做多少道题目?(没有a完就算成小数累加哦w/*这个也算是吴大佬的贡献嘛*/)
输入描述:
输入由多个测试用例组成,每个测试用例是有两个非负整数m(总的精力),n的行作为第一行,然后后面有n行跟随,每行包括两个非负整数w[i],m[i],最后一个测试用例后面有一组 -1 -1(所有的整数都不大于1000,毕竟人类是有极限的嘛hhh)
输出描述:
对于每一个测试用例,在一行中输出吴大佬可以做出的题目数目,精确到小数点后3位
输入样例#:
233 6 6 1 23 66 32 23 66 66 1 5 8 5 -1 -1
输出样例#:
136.000
#include<stdio.h>
#include <bits/stdc++.h>//万能头文件
using namespace std;
struct node{
double w,m;
}p[1005];
bool cmp(node a,node b){
return a.m/a.w <b.m/b.w;
}
int main(){
int x,n;
while(scanf("%d%d",&x,&n) !=EOF){
if(n==-1&&x==-1) break;
for(int i = 1;i<=n;i++)
scanf("%lf%lf",&p[i].w,&p[i].m);
sort(p+1,p+n+1,cmp);
double ans = 0;
for(int i = 1;i<=n;i++){
if(x>p[i].m){
ans += p[i].w;
x-=p[i].m;
}
else{
ans += (p[i].w*x/p[i].m);
break;
}
}
printf("%.3lf",ans);
}
}
骑士的工作
题目背景
你作为一个村的村长,保卫村庄是理所当然的了。今天,村庄里来了一只恶龙,他有 nn 个头,恶龙到处杀人放火。你着急了。不过天无绝人之路,现在来了一个骑士团。里面有 mm 位成员(往下看)。
题目描述
每个人都可以砍掉一个大小不超过 zz 的头,需要 zz 个金币,求最小花费。
输入格式
第一行两个整数 nn,mm。
下接 nn 行,一个整数表示 nn 个头的大小。
下接 mm 行,每个人可以砍的头大小和需要的金币数。
输出格式
一个整数,最小花费。如果无解,输出
you died!
。
输入
2 3 5 4 7 8 4
输出
11
#include<stdio.h>
#include <bits/stdc++.h>//万能头文件
using namespace std;
int main(){
int n,m,i;
int a[20000]; //头的数目
int z[20000];//每个人花费的金钱
cin>>n>>m;
for( i = 1;i<=n;i++)
cin>>a[i];
for( i = 1;i<=m;i++)
cin>>z[i];
sort(a+1,a+1+m);
sort(z+1,z+1+m);
if(n>m){
printf("you died!");
return 0;
}
int ans = 0;
int j = 1;
for ( i;i<=n;i++){
while(a[i]>z[j]) j++;
ans += z[j];
if(j>m) break;
j++;
}
if (i!=n)
printf ("you died!");
else
printf("%d\n",ans);
return 0;
}