Egg Drop

来源:互联网 发布:沈阳市软件行业协会 编辑:程序博客网 时间:2024/06/02 14:53

http://code.google.com/codejam/contest/dashboard?c=agxjb2RlamFtLXByb2RyEAsSCGNvbnRlc3RzGIP6AQw#s=p2

 

Problem

Imagine that you are in a building with F floors (starting at floor 1, the lowest floor), and you have a large number of identical eggs, each in its own identical protective container. For each floor in the building, you want to know whether or not an egg dropped from that floor will break. If an egg breaks when dropped from floor i, then all eggs are guaranteed to break when dropped from any floor j ≥ i. Likewise, if an egg doesn't break when dropped from floor i, then all eggs are guaranteed to never break when dropped from any floor j ≤ i.

We can define Solvable(F, D, B) to be true if and only if there exists an algorithm to determine whether or not an egg will break when dropped from any floor of a building with F floors, with the following restrictions: you may drop a maximum of D eggs (one at a time, from any floors of your choosing), and you may break a maximum of B eggs. You can assume you have at least D eggs in your possession.

Input

The first line of input gives the number of cases, N. N test cases follow. Each case is a line formatted as:

F D B

Solvable(F, D, B) is guaranteed to be true for all input cases.

Output

For each test case, output one line containing "Case #x: " followed by three space-separated integers: Fmax, Dmin, and Bmin. The definitions are as follows:

  • Fmax is defined as the largest value of F' such that Solvable(F', D, B) is true, or -1 if this value would be greater than or equal to 232 (4294967296).
    (In other words, Fmax = -1 if and only if Solvable(232, D, B) is true.)
  • Dmin is defined as the smallest value of D' such that Solvable(F, D', B) is true.
  • Bmin is defined as the smallest value of B' such that Solvable(F, D, B') is true.

Limits

1 ≤ N ≤ 100.

Small dataset

1 ≤ F ≤ 100,
1 ≤ D ≤ 100,
1 ≤ B ≤ 100.

Large dataset

1 ≤ F ≤ 2000000000,
1 ≤ D ≤ 2000000000,
1 ≤ B ≤ 2000000000.

 

这个题目如果一个一个去想,去算的话,估计就糊涂了,其实最主要的是递推公式.

假设F(D,B)表示,D个蛋,可以破B个最高可以测试的楼层数.那么我们去测试的时候,第一个蛋应该放在哪里呢?

可以这样想,如果第一个蛋破了,省下的蛋应该可以把第一个蛋破的那个楼层以下的都检验一遍,也就是F(D-1, B-1)+1

这就是第一个蛋扔的位置,如果从这个位置扔下去蛋不破,那么在这个基础上,还可以测试F(D-1, B)个楼层.

因此F(D, B) = F(D-1, B)+F(D-1, B-1)+1

 

有了递推公式,后面的事情就好办了, 知道D,B,求F,直接递归就行.

有了F,D求B,或者有了F,B求D, 就从小到大遍历B(D),直到当前解满足.

 

下面考虑的就是效率的问题,由于直接递归是O(2^n)时间和空间复杂度的, 所以对于大数,需要做一些优化处理.

首先,计算出一些常用的递归出口.

F(D, D)=2^D-1;

F(D, 1)=D;

F(D, 2)=D*(D+1)/2;

F(D, 3)=(D-1)*D*(D+1)/6+D;

由于题目要求的最大F限制是2^32, 比这个大的都返回-1就可以了.

所以当D和B很大的时候,基本上都是-1, B<=3的时候直接用公式解, B>3的时候, 我们判断D是否足够小似的F(D, 3)<2^32, 否则直接返回-1, 这样就似的很深的递归不会出现.

 

另外, 由于小于2^32的都要返回结果,所以这里采用unsigned long来储存计算结果, 用返回值来控制是否溢出.

 

代码如下:

#include <stdio.h>


#define MAX_VALUE (4294967296UL)

int GetSum(unsigned int nEgg, unsigned int nBreak, unsigned long* nSum)
{
 unsigned long nSum1, nSum2;
 if(nEgg==nBreak)
 {
  if(nEgg>32) return (-1);
  else if(nEgg == 32)
  {
   *nSum = 0xFFFFFFFF;
  }
  else
  {
   *nSum = ((1<<nEgg)-1);
  }
  return 0;
 }
 if(nBreak==3)
 {
  if(nEgg>2953) return (-1);
  else
  {
   unsigned long nAdd;
   nAdd = (nEgg-1)*nEgg/2;
   if(nAdd%3==0)
   {
    *nSum = (nAdd/3*(nEgg+1)+nEgg);
   }
   else
   {
    *nSum = ((nEgg+1)/3*nAdd+nEgg);
   }
   return 0;
  }
 }
 
 if(GetSum(nEgg-1, nBreak, &nSum2)==-1)
 {
  return -1;
 }
 if(GetSum(nEgg-1, nBreak-1, &nSum1)==-1)
 {
  return -1;
 }
 if(nSum1+nSum2+1<nSum1) return (-1);
 *nSum = nSum1+nSum2+1;
 return 0;
}

int GetTotalFloor(int nEgg, int nBreak, unsigned long* pSum)
{
 if(nBreak==1)
 {
  *pSum = nEgg;
  return 0;
 }
 if(nBreak==2)
 {
  if(nEgg>92681) return (-1);
  if(nEgg%2==0)
  {
   *pSum = (nEgg/2*(nEgg+1));
  }
  else
  {
   *pSum = ((nEgg+1)/2*nEgg);
  }
  return 0;
 }
 if(nBreak>=3)
 {
  if(nEgg>2953) return (-1);
 }
 return GetSum(nEgg, nBreak, pSum);
}

int main()
{
 int nRound;
 FILE* fp;
 int i, j;
 fp = fopen("1.txt", "r");
 fscanf(fp, "%d", &nRound);

 for(i=0; i<nRound; i++)
 {
  int nFloor, nEgg, nBreak;
  unsigned long nSum;
  int nRet;
  fscanf(fp, "%d %d %d", &nFloor, &nEgg, &nBreak);
  printf("Case #%d: ", i+1);
  nRet = GetTotalFloor(nEgg, nBreak, &nSum);
  if(nRet == -1) printf("-1 ");
  else printf("%u ", nSum);
  for(j=1; j<nEgg; j++)
  { 
   if(nBreak>j) nRet = GetTotalFloor(j, j, &nSum);
   else nRet = GetTotalFloor(j, nBreak, &nSum);
   if(nRet==-1 || nSum>=(unsigned)nFloor) break;
  }
  printf("%d ", j);

  for(j=1; j<nBreak; j++)
  {
   nRet = GetTotalFloor(nEgg, j, &nSum);
   if(nRet==-1 || nSum>=(unsigned)nFloor) break;
  }
  printf("%d/n", j);
 }
 return 0;
}

原创粉丝点击