#include <iostream>
#include <vector>
#include <limits>
#define DEBUG_TRIAL false
class Trial{
public:
const size_t HEIGHT;
std::string record;
const size_t BREAKING_HEIGHT;
size_t eggs;
size_t start;
size_t end;
size_t floorsLeft(){
return (end-start);
}
size_t middle(){
return start + (floorsLeft()/2UL);
}
size_t drops = 0;
Trial(const size_t BREAKING_HEIGHT, size_t eggs, size_t start, size_t end): BREAKING_HEIGHT(BREAKING_HEIGHT), eggs(eggs), start(start), end(end), HEIGHT(end), record(end, '_'){
record[BREAKING_HEIGHT] = 'B';
}
bool foundAnswer(){
return ((record[0] == 'X') || (record.find("OX")!=std::string::npos));
}
bool drop(size_t height){
#if DEBUG_TRIAL
std::cout << "Start: " << start << ". End: " << end << ". Floors Left: " << floorsLeft() << ". Middle Index: " << middle() << std::endl;
#endif
drops++;
bool cracked = height >= BREAKING_HEIGHT;
if(cracked) --eggs;
record[height] = (height >= BREAKING_HEIGHT)? 'X' : 'O';
#if DEBUG_TRIAL
std::cout << record << std::endl;
#endif
return cracked;
}
size_t nowWhat(){
if(foundAnswer()){
return drops;
}else if(eggs <= 0){
throw "Algorithm failed! No more eggs!";
return 1UL;
}else if(eggs > 1){
return wrecklessSearch();
}else{
return safeSearch();
}
}
size_t safeSearch(){
if(drop(start)){
--end;
}else{
++start;
}
return nowWhat();
}
size_t wrecklessSearch(){
if(drop(middle())){
end -= (floorsLeft()/2UL);
}else{
start += (floorsLeft()/2UL);
}
return nowWhat();
}
size_t search(){
return nowWhat();
}
};
size_t search(const size_t height, const size_t BREAKING_HEIGHT, size_t eggs){
Trial trial(BREAKING_HEIGHT, eggs, 0, height);
return trial.search();
}
class TrialStats {
public:
size_t min = std::numeric_limits<size_t>::max();
size_t max = 0;
double mean = -1.0;
void printStats(){
std::cout << "Minimum drops: " << min << std::endl;
std::cout << "Maximum drops: " << max << std::endl;
std::cout << "Mean drops: " << mean << std::endl;
}
};
TrialStats trial(const size_t HEIGHT, const size_t eggs){
TrialStats stats;
int totaldrops = 0;
for (int breakingHeight = 0; breakingHeight < HEIGHT; ++breakingHeight) {
size_t drops = search(HEIGHT, breakingHeight, eggs);
stats.min = std::min(stats.min, drops);
stats.max = std::max(stats.max, drops);
totaldrops += drops;
}
stats.mean = static_cast<double>(totaldrops) / HEIGHT;
return stats;
}
void testTower(const size_t height, const size_t MAX_EGGS){
for (int eggs = 1; eggs <= MAX_EGGS; ++eggs) {
std::cout << "Building height: " << height << ". Num eggs: " << eggs << std::endl;
TrialStats stats = trial(height, eggs);
stats.printStats();
std::cout << std::endl << std::endl;
}
}
void benchmark(const size_t MAX_HEIGHT){
const size_t MAX_EGGS = 2;
for (size_t height = 1; height <= MAX_HEIGHT; ++height) {
testTower(height, std::min(height, MAX_EGGS));
}
}
int main() {
constexpr size_t MAX_HEIGHT = 36;
benchmark(MAX_HEIGHT);
return 0;
}