【蓝桥杯】巧克力—贪心思想求解

文章讲述了如何使用优先考虑价格最低且临近过期的巧克力的策略来解决一个数学问题。初始的贪心思路被证明是错误的,因为局部最优并不保证全局最优。正确的解决方案是通过排序和结构体存储巧克力信息,然后按保质期临近的顺序分配,确保最小化成本。
摘要由CSDN通过智能技术生成

问题描述:

题解分析:

错误思想:本来的想法是先使用低价格的巧克力,并且判断需要吃几块【其中内容比较细】,直接计算即可,但是本题好像不可以用简单的最小价格的贪心来做

正确思路:创建一个结构体存储每种巧克力的信息,创建一个set集合来存储哪一天未吃巧克力;

创建一个数组来存储多种巧克力的信息,并按照价格升序排序,价格相同,则按照保质期升序排序

如何安排小兰每天吃哪一款巧克力?

1.先吃最便宜的

2.但是问题是哪一天吃最便宜的?答案就是:邻接过期的哪一天吃

举例:假如一个巧克力A单价1、保质期3天,数量2,巧克力B单价2、保质期5,数量三;而小兰要

吃 8 天,那么优先安排小兰第3天吃A,第2天吃A,此时巧克力A已经吃完了;再安排吃巧克力B,

安排第5天吃B,第四天吃B,第一天吃B;就是这个思路

核心总结就是:先吃便宜的,在临过期的时间吃

解题代码:

贪心思路写的:不正确

错误出现在:局部最优不是全局最优

错误版本:(未全部通过)

//蓝桥国赛吃巧克力 
#include <bits/stdc++.h>
using namespace std;
int a[100050];
int b[100050];
int c[100050];
bool vis[100050];    //监督数组 
long long int pos = 0;   //当前可以吃的天数
long long int ans = 0;  //最后需要花费的价钱 
int x,n;
//筛选出价格最便宜的巧克力
int find(int* te,bool* tee)
{
	int maxx = 1e9+100;
	int T_i=0;
	for(int p=1;p<=n;++p){
		if(a[p]<maxx && tee[p]==false){
			maxx = a[p];
			T_i = p;
		}
	}
	return T_i;
} 
int main(){
	cin>>x>>n;
	for(int i=1;i<=n;++i){
		cin>>a[i]>>b[i]>>c[i];   //第 i 种巧克力的信息 
	}
	//从最简单的开始计算
	while(pos<x)
	{
		//判断终止条件
		//1.找到最便宜的价格的下标
		int chept = find(a,vis);
		vis[chept] = true;
		int ts = b[chept] - pos;
		//2.判断当前最便宜的巧克力的天数是否满足已经过的天数
		if(ts>0){
			//开始判断剩余的天数 
			int mm = x - pos;
			if(ts > mm && c[chept]>mm){
				pos += mm;
				ans += mm*a[chept];
				break;
			}
			else if(ts > mm && c[chept]<mm){
				pos += c[chept];
				ans += c[chept]*a[chept];
				continue;
			}
			//说明还有可以买的
			//不用一下子买这么多---买几个这问题一定好好想清楚
			int ww = 1; 
			if(ts<=c[chept]){
				pos += ts;
				ww = ts;
			}	
			else {
				pos += c[chept];
				ww = c[chept];
			}
			ans += (ww*a[chept]);
		}		
	}
	printf("%lld\n",ans);
	//cout<<ans<<endl;	
	return 0;
}

AC版本:

一定要开 long long 来存储 ans 和 pos;

//蓝桥国赛吃巧克力 
#include <bits/stdc++.h>
using namespace std;
const int mmd = 1e5+100;
typedef long long ll;
typedef struct node{
	int a,b,c;
	bool operator<(node &jb){
		if(a == jb.a && b < jb.b)
			return b < jb.b;
		return a < jb.a;
			
	}
}node;
node md[mmd];
set<int> ms;   //存放未处理的日子 
int main(){
	int x,n;
	cin>>x>>n;
	for(int i=1;i<=n;++i){
		cin>>md[i].a>>md[i].b>>md[i].c;   //第 i 种巧克力的信息 
	}
	for(int i=1;i<=x;++i){
		ms.insert(i);
	}  //赋初值 
	//排序
	sort(md+1,md+1+n); 
	//一个一个处理
	ll pos = 1;  //第一个巧克力 
	ll ans = 0;
	while(ms.size() && pos<=n)     //当有未处理的天数以及未处理完巧克力时 
	{
		while(md[pos].c && ms.size() && *ms.begin()<=md[pos].b)   //当前要处理的天数小小于保质期数 
		{
			ans += md[pos].a;
			md[pos].c--;
			//获取那个比保质期最近的那个时间
			auto it = ms.upper_bound(md[pos].b);    //第一个大于该数的
			it--;   //指向该数
			ms.erase(it); 
		}
		pos++; 
	}
	if(ms.size())
		cout<<-1<<endl;
	else cout<<ans<<endl;	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hskwcy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值