codechef Ciel and Receipt题解

本文探讨如何运用贪心算法解决一个特定的餐厅点餐问题,即求解给定价格p时,所需的菜单组合数量最少。通过分析菜单价格规律,实现高效的求解过程,特别适用于数据特殊的情况下,提供快速且准确的解决方案。

Tomya is a girl. She loves Chef Ciel very much.

Tomya like a positive integer p, and now she wants to get a receipt of Ciel's restaurant whose total price is exactly p.
The current menus of Ciel's restaurant are shown the following table.

Name of Menu price
eel flavored water 1
deep-fried eel bones 2
clear soup made with eel livers 4
grilled eel livers served with grated radish 8
savory egg custard with eel 16
eel fried rice (S) 32
eel fried rice (L) 64
grilled eel wrapped in cooked egg 128
eel curry rice 256
grilled eel over rice 512
deluxe grilled eel over rice 1024
eel full-course 2048

Note that the i-th menu has the price 2i-1 (1 ≤ i ≤ 12).

Since Tomya is a pretty girl, she cannot eat a lot.
So please find the minimum number of menus whose total price is exactly p.
Note that if she orders the same menu twice, then it is considered as two menus are ordered. (SeeExplanations for details)

Input

The first line contains an integer T, the number of test cases.
Then T test cases follow.
Each test case contains an integer p.

Output

For each test case, print the minimum number of menus whose total price is exactly p.

Constraints

1 ≤ T ≤ 5
1 ≤ p ≤ 100000 (105)
There exists combinations of menus whose total price is exactly p.

Sample Input

4
10
256
255
4096

Sample Output

2
1
8
2

本题由于数据特殊,原来可以使用贪心法的。

时间效率可以达到O(1),因为最后有个1的数组能被任何整数整除,所以是必然有解的。

#include <stdio.h>

int CielandReceiptCal()
{
	const static int MENUS_NUM = 12;

	int T;
	scanf("%d", &T);
	while (T--)
	{
		int P;
		scanf("%d", &P);
		int largest = 2048, ans = 0;
		for (int i = MENUS_NUM - 1; i >= 0 ; i--)
		{
			ans += P / largest;
			P %= largest;
			largest >>= 1;
		}
		printf("%d\n", ans);
	}
	return 0;
}

当然无数据特殊性的时候,就要使用dp了:

int CielandReceiptDP()
{
	const static int MENUS_NUM = 12;
	const static int MENUS[MENUS_NUM] = {1, 2, 4, 8, 16, 32, 64, 
		128, 256, 512, 1024, 2048};

	int T;
	scanf("%d", &T);
	while (T--)
	{
		int P;
		scanf("%d", &P);
		int *tbl = new int[P+1];//这里的[]写成()错误
		tbl[0] = 0;
		for (int i = 1; i <= MENUS_NUM; i++)
		{
			for (int j = MENUS[i-1]; j <= P; j++)
			{
				tbl[j] = tbl[j-MENUS[i-1]] + 1;
			}//处理4096000上百万个数据也能秒杀
		}
		printf("%d\n", tbl[P]);
		delete [] tbl;
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值