//ProjectEuler/C++/Source/Problem18.hpp //Matthew Ellison // Created: 11-01-18 //Modified: 07-14-19 //Find the maximum total from top to bottom /* 75 95 64 17 47 82 18 35 87 10 20 04 82 47 65 19 01 23 75 03 34 88 02 77 73 07 63 67 99 65 04 28 06 16 70 92 41 41 26 56 83 40 80 70 33 41 48 72 33 47 32 37 16 94 29 53 71 44 65 25 43 91 52 97 51 14 70 11 33 28 77 73 17 78 39 68 17 57 91 71 52 38 17 14 91 43 58 50 27 29 48 63 66 04 68 89 53 67 30 73 16 69 87 40 31 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23 */ //This is done using a breadth first search //Unless otherwise listed all non-standard includes are my own creation and available from https://bibucket.org/Mattrixwv/myClasses /* Copyright (C) 2019 Matthew Ellison This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include #include #include #include #include "Stopwatch.hpp" #include "../Headers/Problem18.hpp" std::vector Problem18::list[NUM_ROWS] = {{75}, {95, 64}, {17, 47, 82}, {18, 35, 87, 10}, {20, 04, 82, 47, 65}, {19, 01, 23, 75, 03, 34}, {88, 02, 77, 73, 07, 63, 67}, {99, 65, 04, 28, 06, 16, 70, 92}, {41, 41, 26, 56, 83, 40, 80, 70, 33}, {41, 48, 72, 33, 47, 32, 37, 16, 94, 29}, {53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14}, {70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57}, {91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48}, {63, 66, 04, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31}, {04, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 04, 23}}; Problem18::Problem18() : Problem("Find the maximum total from the top to the bottom of the pyramid."), actualTotal(0){ } void Problem18::invert(){ for(unsigned int rowCnt = 0;rowCnt < NUM_ROWS;++rowCnt){ for(unsigned int colCnt = 0;colCnt < list[rowCnt].size();++colCnt){ list[rowCnt][colCnt] = 100 - list[rowCnt][colCnt]; } } } void Problem18::solve(){ //If the problem has already been solved do nothing and end the function if(solved){ return; } //Start the timer timer.start(); //The method that I am using looks for the smallest numbers, so I need to invert the numbers in this list invert(); //Now l[i][j] == 100 - l[i][j]; //Add the top point because that is already the only path foundPoints.emplace_back(0, 0, list[0][0], false); //Add the second row as possible points possiblePoints.emplace_back(0, 1, (list[0][0] + list[1][0]), true); possiblePoints.emplace_back(1, 1, (list[0][0] + list[1][1]), false); bool foundBottom = false; //Used when you find a point at the bottom //Loop until you find the bottom while(!foundBottom){ //Check which possible point gives us the lowest number. If more than one has the same number simply keep the first one location minLoc = possiblePoints.front(); for(location loc : possiblePoints){ if(loc.total < minLoc.total){ minLoc = loc; } } //Remove it from the list of possible points possiblePoints.remove_if([minLoc](location loc){return (loc.xLocation == minLoc.xLocation) &&(loc.yLocation == minLoc.yLocation);}); foundPoints.push_back(minLoc); //Add to the list of possible points from the point we just found and //If you are at the bottom raise the flag to end the program int xLoc = minLoc.xLocation; int yLoc = minLoc.yLocation + 1; //Add one because you will always be moving to the next row if(yLoc >= NUM_ROWS){ foundBottom = true; } else{ possiblePoints.emplace_back(xLoc, yLoc, minLoc.total + list[yLoc][xLoc], true); ++xLoc; //Advance the x location to simulate going right possiblePoints.emplace_back(xLoc, yLoc, minLoc.total + list[yLoc][xLoc], false); } } actualTotal = ((100 * NUM_ROWS) - foundPoints.back().total); //Change the minimum to the maximum invert(); //Invert the list again so that it is back to it's original form //Stop the timer timer.stop(); //Throw a flag to show the problem is solved solved = true; } std::string Problem18::getString() const{ //If the problem hasn't been solved throw an exception if(!solved){ throw unsolved(); } std::stringstream results; results << "The value of the longest path is " << actualTotal; return results.str(); } std::string Problem18::getPyramid(){ //If the problem hasn't been solved throw an exception if(!solved){ throw unsolved(); } std::stringstream results; //Print the triangle list of numbers for(unsigned int rowCnt = 0;rowCnt < NUM_ROWS;++rowCnt){ for(unsigned int colCnt = 0;colCnt < list[rowCnt].size();++colCnt){ results << std::setw(2) << list[rowCnt][colCnt] << ' '; } } return results.str(); } std::string Problem18::getTrail(){ //If the problem hasn't been solved throw an exception if(!solved){ throw unsolved(); } std::stringstream results; //Print the trail the algorithm took std::list trail; trail.push_front(foundPoints.back()); bool top = false; while(!top){ bool found = false; int loc = foundPoints.size() - 1; std::list::iterator toAdd = foundPoints.begin(); while(!found){ if(loc < 0){ results << "Error: Location < 0\n"; exit(1); } std::list::iterator it = foundPoints.begin(); std::advance(it, loc); if(trail.front().fromRight){ if((it->xLocation == trail.begin()->xLocation) && (it->yLocation == (trail.begin()->yLocation - 1))){ found = true; toAdd = it; } else{ --loc; } } else{ if((it->xLocation == (trail.begin()->xLocation - 1)) && (it->yLocation == (trail.begin()->yLocation - 1))){ found = true; toAdd = it; } else{ --loc; } } } trail.push_front(*toAdd); if(trail.begin()->yLocation == 0){ top = true; } } for(location loc : trail){ results << list[loc.yLocation][loc.xLocation] << "->"; } return results.str(); } int Problem18::getTotal() const{ //If the problem hasn't been solved throw an exception if(!solved){ throw unsolved(); } return actualTotal; } void Problem18::reset(){ Problem::reset(); foundPoints.clear(); possiblePoints.clear(); actualTotal = 0; }