2021.01.19 模拟赛错题(3)

这篇博客探讨了如何利用贪心算法解决两个实际问题:一是制定营养膳食计划,最大化摄入脂肪的同时遵循食物类别限制;二是计算在特定规则下的最低运输费用。通过对输入数据的排序和优先级队列的应用,这两个问题都能有效地找到最优解。贪心策略在这类问题中展示了其高效性和实用性。

贪心

5.营养膳食

【问题描述】
阿月正在女朋友宁宁的监督下完成自己的增肥计划。为了增肥,阿月希望吃到更多的脂肪。然而也不能只吃高脂肪食品,那样的话就会导致缺少其他营养。阿月通过研究发现:真正的营养膳食规定某类食品不宜一次性吃超过若干份。比如就一顿饭来说,肉类不宜吃超过1份,鱼类不宜吃超过1份,蛋类不宜吃超过1份,蔬菜类不宜吃超过2份。阿月想要在营养膳食的情况下吃到更多的脂肪,当然阿月的食量也是有限的。
【输入格式】
第一行包含三个正整数n(n≤200),m(m≤100)和k(k≤100)。表示阿月每顿饭最多可以吃m份食品,同时有n种食品供阿月选择,而这n种食品分为k类。第二行包含k个不超过10的正整数,表示可以吃1到k类食品的最大份数。接下来n行每行包括2个正整数,分别表示该食品的脂肪指数ai和所属的类别bi,其中ai≤100,bi≤k。
【输出格式】一个数字即阿月可以吃到的最大脂肪指数和。
【样例输入】
6 6 3
3 3 2
15 1
15 2
10 2
15 2
10 2
5 3
【样例输出】60

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string> 
using namespace std;
struct food{
	int value,kind;//指数和种类
}p[300];
bool cmp(food x,food y){
	return x.value>y.value;//按指数大小排
}
int main() {
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	int max[105];
	for(int i=1;i<=k;i++){
		scanf("%d",&max[i]);//最大份数
	}
	for(int i=1;i<=n;i++){
		scanf("%d%d",&p[i].value,&p[i].kind);
	}
	sort(p+1,p+1+n,cmp);
	int ans=0,place=1;
	while(m--){//吃够份数就停止
		while(max[p[place].kind]==0) place++;//如果这个种类的食物吃完了就看下一个能不能吃
		max[p[place].kind]--;//吃掉就减
		ans+=p[place].value;//吃
		place++;//指下一个
	}
	printf("%d",ans);
	return 0;
}


6.运输

【问题描述】
现在已知N件商品。和搬运它们其中每一件的费用。现在搬家公司的老板Mr.B决定让我们每次任意选取2件商品。然后这2件商品只算一件商品的费用。但是这个商品的搬运费用是将选出的2个商品的费用之和除以K的运算结果。如此反复。直到只收一件商品的钱。这个就是商店要付的费用。想尽可能的少付钱,以便将更多的钱卷给希望工程。所以请你帮他计算一下最少只用付多少钱。
【输入格式】n,k w1,w2,…,wn(每一件商品的搬运费用)
【输出格式】输出一个数字,表示最少付多少钱。
【输入样例】
5 2
1 2 3 4 5

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue> 
#include<functional> 
#include<vector> 
using namespace std;
bool cmp(int x,int y){
	return x>y;
}
int main() {
	int x,n,k;
	priority_queue<int,vector<int>,less<int> >q;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		q.push(x);
	} 
	for(int i=1;i<=n-1;i++){
		int a,b;
		a=q.top();
		q.pop();
		b=q.top();
		q.pop();
		a+=b;
		a/=k;
		q.push(a);
	}
	int ans=q.top();
	printf("%d",ans);
	return 0;
}

解法类似合并果子。

7.最佳旅游路线

某旅游区的街道成网格状。其中东西向的街道都是旅游街,南北向的街道都是林荫道。由于游客众多,旅游街被规定为单行道,游客在旅游街上只能从西向东走,在林阴道上则既可从南向北走,也可以从北向南走。阿龙想到这个旅游区游玩。他的好友阿福给了他一些建议,用分值表示所有旅游街相邻两个路口之间的街道值得游览的程度,分值时从-100到100的整数,所有林阴道不打分。所有分值不可能全是负分。例如图是被打过分的某旅游区的街道图:
在这里插入图片描述
阿龙可以从任一个路口开始游览,在任一个路口结束游览。请你写一个程序,帮助阿龙找一条最佳的游览线路,使得这条线路的所有分值总和最大。
在这里插入图片描述

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string> 
using namespace std;
int m,n,x[105][20010];
int best[20020];
int ans=-100005,now=-100005;
int main() {
	scanf("%d%d",&m,&n);
	n++;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n-1;j++){
			scanf("%d",&x[i][j]);
		}
	}
	for(int i=1;i<=n;i++) best[i]=-1000;
	now=0;	
	for(int j=1;j<=n-1;j++){
		for(int i=1;i<=m;i++){
			best[j]=max(best[j],x[i][j]);
		}
		now+=best[j];
		if(now<0) now=0;
		ans=max(ans,now);
	}
	printf("%d",ans);
	return 0;
}

倦了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值