文具订购(【CCF】NOI Online能力测试 入门组第一题)

【题目描述】

小明的班上共有 n 元班费,同学们准备使用班费集体购买 3 种物品:
1.圆规,每个 7 元。
2.笔,每支 4 元。
3.笔记本,每本 3 元。
小明负责订购文具,设圆规,笔,笔记本的订购数量分别为 a,b,c,他订购的原则依次如下:
1.n 元钱必须正好用光,即 7a+4b+3c=n。
2.在满足以上条件情况下,成套的数量尽可能大,即 a,b,c 中的最小值尽可能大。
3.在满足以上条件情况下,物品的总数尽可能大,即 a+b+c 尽可能大。
请你帮助小明求出满足条件的最优方案。可以证明若存在方案,则最优方案唯一。

【输入格式】

从文件 order.in 中读入数据。
仅一行一个整数 n 表示班费数量。

【输出格式】

输出到文件 order.out 中。
若方案不存在则输出 -1。否则输出一行三个用空格分隔的非负整数 a,b,c 表示答案。

【样例1输入】

1

【样例1输出】

-1

【样例2输入】

14

【样例2输出】

1 1 1

【样例3输入】

33

【样例3输出】

1 2 6

【样例3解释】

a=2,b=4,c=1 也是满足条件 1,2 的方案,但对于条件 3,该方案只买了 7 个物品,不如 a=1,b=2,c=6 的方案。

【数据范围与提示】

对于测试点 1 ∼ 6:n ≤ 14。
对于测试点 7 ∼ 12:n 是 14 的倍数。
对于测试点 13 ∼ 18:n ≤ 100。
对于所有测试点:0 ≤ n ≤ 105。

【时间限制】

1.0s

【空间限制】

256MB

暴力法:

#include<iostream>
#include<algorithm>
using namespace std;
int n,x,m=-1,sum=0,ans[3]={0};
void order(int n)
{
	for(int a=0;a<=n/7;a++)
		for(int b=0;b<=n/4;b++)
			for(int c=0;c<=n/3;c++)
				if(7*a+4*b+3*c==n)//满足条件1 
				{
					x=min(min(a,b),c);
					if(x>m)//满足条件1判断条件2 决定最优 
					{
						ans[0]=a,ans[1]=b,ans[2]=c;
						m=x;
						sum=a+b+c;
					}
					else if(x=m)//都满足条件1,2,判断条件3 决定最优 
					{
						int y=a+b+c;
						if(y>sum)
						{
							ans[0]=a,ans[1]=b,ans[2]=c;
							sum=y;
							m=x; 
						}
					}
				}
}
int main()
{
	freopen("order.in","r",stdin);
	freopen("order.out","w",stdout);
	cin>>n;
	order(n);
	if(ans[0]==0)
		cout<<"-1";
	else
		cout<<ans[0]<<" "<<ans[1]<<" "<<ans[2];
	fclose(stdin);
	fclose(stdout);
	return 0;
 } 

O(1)算法

分析:

1.发现除了n=1n=2,n=5以外,任何的价格n都可以被花光
2.条件二就是要我们尽可能地买更多的整14元
3.如果买完尽量多的套数以后,剩下的是1,2,5元呢?
那我们就少一套14元的,拿出来变成剩下15,17,19元,然后就大功告成了

AC的C++代码如下:

(带码有点长,但思路简单啊,只要在n的范围内都秒解)

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int n,ans=0;//ans用来记录套数
	cin>>n;
	if(n==0)//若n=0,则直接输出答案;
	{
    	cout<<0<<" "<<0<<" "<<0;
    	return 0;
  	}
	if(n<6 && n!=4 && n!=3)//若n无为1,2,5,则直接输出答案;
  	{
    	cout<<"-1";
    	return 0;
 	}
  	ans=n/14;
  	n%=14;
  	if(n<6 && n!=4 && n!=3 && n!=0)
    	ans--,n+=14;//若在套数最多时n分不完,套数-1;
	else if(n==0)//若正好分完,直接输出三个套数
    {
        cout<<ans<<" "<<ans<<" "<<ans<<endl;
        return 0;
    }   
   	switch(n)//特判 
   	{
	case 3: cout<<ans<<" "<<ans<<" "<<ans+1<<endl;	break;             
    case 4: cout<<ans<<" "<<ans+1<<" "<<ans<<endl;	break; 
    case 6: cout<<ans<<" "<<ans<<" "<<ans+2<<endl;	break; 
    case 7: cout<<ans<<" "<<ans+1<<" "<<ans+1<<endl;break; 
    case 8: cout<<ans<<" "<<ans+2<<" "<<ans<<endl; 	break;  
    case 9: cout<<ans<<" "<<ans<<" "<<ans+3<<endl;	break; 
    case 10:cout<<ans<<" "<<ans+1<<" "<<ans+2<<endl;break; 
    case 11:cout<<ans<<" "<<ans+2<<" "<<ans+1<<endl;break; 
    case 12:cout<<ans<<" "<<ans<<" "<<ans+4<<endl;	break; 
    case 13:cout<<ans<<" "<<ans+1<<" "<<ans+3<<endl;break; 
	case 15:cout<<ans<<" "<<ans<<" "<<ans+5<<endl;  break;       
	case 16:cout<<ans<<" "<<ans+1<<" "<<ans+4<<endl;break; 
	case 19:cout<<ans<<" "<<ans+1<<" "<<ans+5<<endl;break; 
 	}
  return 0;
}
传送门:跑步(【CCF】NOI Online能力测试 入门组第二题)
魔法(【CCF】NOI Online能力测试 入门组第三题)
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值