题意是给一个N*M*K的立方体巧克力,求分别用手掰和用刀切将其分为 1 * 1 * 1的小立方体最少的步骤数。
开始的时候一点思路都没有,接下来带入数字开始死算。
当巧克力为平面时:eg.1。 2 * 2 的巧克力手掰需要 2 * 2 -1 步;刀切需要 log2(2 * 2) = 2 步。
2。 5 * 4的巧克力手掰需要 5 * 4 - 1 步;刀切需要 log2 (5 * 4)取上界 = 5 步。
推广到立体,结论为:手掰需要 N * M * K - 1 步, 刀切需要 log2 (N * M *K )取上界步。
由于log2 (N * M *K )中 N * M *K比较大,所以利用数学公式将其缩小:log2 (N * M *K ) = log2(N) + log2(M) + log2(K)。
刚开始的时候没注意到这里,打表打大了。
代码:
#include <stdio.h>
__int64 log2[] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};
int knife(int x)
{
for (int i = 0; i < 15; i++)
{
if (x == log2[i])
{
x = i;
break;
}
if (x > log2[i] && x < log2[i + 1])
{
x = i + 1;
break;
}
}
return x;
}
int main()
{
/*freopen("out.txt", "w", stdout);
long long num = 1;
int count = 0;
for (int i = 0; i < 100; i++)
{
num *= 2;
printf("%lld,", num);
count ++;
if (num >= 8000000000)
{
printf("\n\n%d", count);
break;
}
}*/
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
for (int i = 1; i <= ncase; i++)
{
printf("Case #%d:", i);
__int64 N, M, K;
scanf("%I64d%I64d%I64d", &N, &M, &K);
__int64 ans = N * M * K;
printf(" %I64d ", ans - 1);
ans = knife(N) + knife(M) + knife(K);
printf("%I64d\n", ans);
}
return 0;
}
另一种写法:
#include <cstdio>
typedef __int64 LL;
int knife(int x) {
int tmp = 0;
while (x != 1) {
if (x&1)
x++; //x 为奇数时加一为偶数 如: 7/2 = 3 其实应该二分 4
x /= 2;
tmp++;
}
return tmp;
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif // LOCAL
int tcase, cc = 1;
scanf("%d", &tcase);
while (tcase--) {
LL n, m, k;
scanf("%I64d%I64d%I64d", &n, &m, &k);
int tt = knife(n) + knife(m) + knife(k);
printf("Case #%d: %I64d %d\n", cc++, m*n*k - 1, tt);
}
return 0;
}