小学期高级班 A 题 - Break the Chocolate

3 篇文章 0 订阅
1 篇文章 0 订阅

记录渣渣的第一次。。。


原题目

Description

Benjamin is going to host a party for his big promotion coming up.

Every party needs candies, chocolates and beer, and of course Benjamin has prepared some of those. But as everyone likes to party, many more people showed up than he expected. The good news is that candies are enough. And for the beer, he only needs to buy some extra cups. The only problem is the chocolate.

As Benjamin is only a 'small court officer' with poor salary even after his promotion, he can not afford to buy extra chocolate. So he decides to break the chocolate cubes into smaller pieces so that everyone can have some.

He have two methods to break the chocolate. He can pick one piece of chocolate and break it into two pieces with bare hand, or put some pieces of chocolate together on the table and cut them with a knife at one time. You can assume that the knife is long enough to cut as many pieces of chocolate as he want.

The party is coming really soon and breaking the chocolate is not an easy job. He wants to know what is the minimum number of steps to break the chocolate into unit-size pieces (cubes of size 1 × 1 × 1). He is not sure whether he can find a knife or not, so he wants to know the answer for both situations.

Input

The first line contains an integer T(1<= T <=10000), indicating the number of test cases.
Each test case contains one line with three integers N,M,K(1 <=N,M,K <=2000), meaning the chocolate is a cube of size N ×M × K.

Output

For each test case in the input, print one line: "Case #X: A B", where X is the test case number (starting with 1) , A and B are the minimum numbers of steps to break the chocolate into N × M × K unit-size pieces with bare hands and knife respectively.

Sample Input
2
1 1 3
2 2 2

Sample Output
Case #1: 2 2
Case #2: 7 3


///


第一个想到的思路是把每次巧克力的状态看成一个结点,于是「用手掰」就是每次只处理一个结点,所以实际上是求内部结点数;而「一刀切」就是可以一层一层的分,相当于求树的层数。

下面的代码的构造树的方法是从最后一维开始分一块,直到最后一维不可分,接着分第二维。


#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

int high(int p, int q, int k)
{
	if (k != 1)
		return max(high(p, q, 1), high(p, q, k-1))+1;
	if (q != 1)
		return max(high(p, 1, 1), high(p, q-1, 1))+1;
	if (p != 1)
		return max(1, high(p-1, 1, 1))+1;
	return 1;
}

int internal(int p, int q, int k)
{
	if (k != 1)
		return internal(p, q, 1)+internal(p, q, k-1)+1;
	if (q != 1)
		return internal(p, 1, 1)+internal(p, q-1, 1)+1;
	if (p != 1)
		return internal(p-1, 1, 1)+1;
	return 0;
}

int main()
{
	int t,p,q,k,index=1;
	cin >> t;
	while (t--)
	{
		cin >> p >> q >> k;
		cout << "Case #" << index++ << ": ";
		cout << internal(p,q,k) << " " << high(p,q,k)-1 << endl;
	} 

	//system("pause");
	return 0;
}

显然,用递归来写树是最简便的,但是也显然会超时。当三个数都是2000的时候,根本就等不到答案,所以剪下枝呗。(发现最大输入时,结果是负数,所以也改成 long long)


#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

long long high(long long p, long long q, long long k)
{
	if (k != 1)
		return max(p+q-1, high(p, q, k-1))+1;
	if (q != 1)
		return p+q-1;
	if (p != 1)
		return p;
	return 1;
}

long long internal(long long p, long long q, long long k)
{
	return k * (q*(p-1)+q-1) + k-1;
}

int main()
{
	int t,index=1;
	long long p,q,k;
	cin >> t;
	while (t--)
	{
		cin >> p >> q >> k;
		cout << "Case #" << index++ << ": ";
		cout << internal(p,q,k) << " " << high(p,q,k)-1 << endl;
	}
	//system("pause");
	return 0;
}

很好,这次貌似没有超时了,但是提交之后是 Wrong Answer,想了一下,发现是建树的方法不对,这样不能保证最小高度。建树应该尽可能平分该维,所以。


#include <iostream>
#include <algorithm>
#include <string>
#include <stdio.h>
using namespace std;

long long high(long long p, long long q, long long k)
{
	if (k != 1)
		return max(high(p, q, k/2), high(p, q, k-k/2))+1;
	if (q != 1)
		return max(high(p, q/2, 1), high(p, q-q/2, 1))+1;
	if (p != 1)
		return p;
	return 1;
}

long long internal(long long p, long long q, long long k)
{
	return k * (q*(p-1)+q-1) + k-1;
}

int main()
{
	int t,index=1;
	long long p,q,k;
	cin >> t;
	while (t--)
	{
		scanf("%I64d %I64d %I64d", &p, &q, &k);
		printf("Case #%d: %I64d %I64d", index++, internal(p,q,k), high(p,q,k)-1);
	}
	//system("pause");
	return 0;
}

结果还是超时,连 C 输入输出都换了,所以结论是:这种方法做不了!


后来经过某几位大牛的指点,其实是可以分开三个维度来考虑,也就是贪婪算法。所以,下面是最终通过的版本=_=


#include <iostream>
#include <algorithm>
#include <string>
#include <stdio.h>
#include <cmath>
using namespace std;

int main()
{
	int t,index=1;
	long long p,q,k;
	cin >> t;
	while (t--)
	{
		scanf("%I64d %I64d %I64d", &p, &q, &k);
		printf("Case #%d: %I64d %d\n", index++,  k*(q*(p-1)+q-1)+k-1, 
			int(ceil(log2(p)))+int(ceil(log2(q)))+int(ceil(log2(k))));
	}
	//system("pause");
	return 0;
}


Skill

首先有关取整的 C++ 函数,ceil() 和 floor() 使用,还有类型 long long 的 C 输入输出。纯数学题。


Reference Link

C/C++ 取整函数ceil(),floor()   http://blog.163.com/chen_dawn/blog/static/112506320117893146230/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值