【c/c++编程】贪心问题

目录

贪心算法

喝饮料

组队刷题

骑士的工作


贪心算法

贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。

贪心类问题是很常见的考点,贪心算法更重要的是一种贪心的思想,它追求的是当前最优解,从而得到全局最优解

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

举例说明

  • 例子 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;
		}
	

猜你喜欢

转载自blog.csdn.net/m0_51933492/article/details/127304210