Использует goto законный способ вырваться из двух циклов?
Я решаю задачу 9 на Project Euler. В моем решении я использую инструкцию "goto" , чтобы вырваться из двух для циклов. Проблема заключается в следующем:
Пифагорейский триплет представляет собой набор из трех натуральных чисел, a b c, для которых
a ^ 2 + b ^ 2 = c ^ 2
Например, 3 ^ 2 + 4 ^ 2 = 9 + 16 = 25 = 52.
Существует ровно один пифагорейский триплет, для которого a + b + c = 1000. Найдите продукт abc.
Мое решение находится в С++:
int a,b,c;
const int sum = 1000;
int result = -1;
for (a = 1; a<sum; a++){
for (b = 1; b < sum; b++){
c = sum-a-b;
if (a*a+b*b == c*c){
result = a*b*c;
goto found;
}
}
}
found:
std::cout << "a:" << a << std::endl;
std::cout << "b:" << b << std::endl;
std::cout << "c:" << c << std::endl;
std::cout <<"Result:" << result << std::endl;
Так как инструкции "goto" не очень популярны среди программистов на С++, я хотел бы знать, если это можно считать разумным использованием "goto" . Или если есть лучшее решение проблемы, которая не нуждается в "goto" . Тем самым я не имею в виду решение, которое просто избегает "goto" , но которое позволяет избежать "goto" таким образом, чтобы улучшить алгоритм.
Ответы
Ответ 1
return
- это "структурированный" goto
, который многие программисты считают более приемлемым! Итак:
static int findit(int sum, int* pa, int* pb, int* pc)
{
for (int a = 1; a<sum; a++) {
for (int b = 1; b < sum; b++) {
int c = sum-a-b;
if (a*a+b*b == c*c) {
*pa = a; *pb = b; *pc = c;
return a*b*c;
}
}
return -1;
}
int main() {
int a, b, c;
const int sum = 1000;
int result = findit(sum, &a, &b, &c);
if (result == -1) {
std::cout << "No result!" << std::endl;
return 1;
}
std::cout << "a:" << a << std::endl;
std::cout << "b:" << b << std::endl;
std::cout << "c:" << c << std::endl;
std::cout <<"Result:" << result << std::endl;
return 0;
}
Ответ 2
По-моему, хорошо использовать goto
в такой ситуации.
Btw, снисходительная проповедь против goto обычно исходит от людей, которые просто попугают то, что слышали другие, говорят или читают где-то..
Ответ 3
См. этот вопрос о выходе из 2 циклов. Есть гораздо лучшие ответы, чем использование goto.
Лучший ответ - разместить второй цикл в функции и вызвать эту функцию из вашего первого цикла.
код, скопированный из ответа mquander
public bool CheckWhatever(int whateverIndex)
{
for(int j = 0; j < height; j++)
{
if(whatever[whateverIndex][j]) return false;
}
return true;
}
public void DoubleLoop()
{
for(int i = 0; i < width; i++)
{
if(!CheckWhatever(i)) break;
}
}
Хотя я чувствую, что использование goto в этом случае не так уж плохо, как убийство котят. Но это близко.
Ответ 4
Я не могу придумать лучшую альтернативу. Но одна альтернатива, не использующая goto
, будет изменять первый for
-loop:
for (a = 1; a<sum && result == -1; a++){
Тогда break
из второго for
-loop. Это будет работать, если результат не будет -1
после того, как второй for
-loop был разбит на break
.
Ответ 5
Вы можете объявить bool found = false
вверху, а затем добавить && !found
в свои условные выражения цикла (после a < sum
и b < sum
), а затем установить найденное значение true, где находится текущее значение goto. Затем сделайте свой вывод условным, если оно будет истинным.
Ответ 6
Я только что нашел это на боковой панели. Интересная нить в целом, но, в частности, this является ответом на мой вопрос.
Ответ 7
int a,b,c,sum = 1000;
for (a = 1; a<sum; ++a)
for (b = 1; b<sum; ++b){
c = sum-a-b;
if (a*a+b*b == c*c) sum = -a*b*c;
}
printf("a: %d\n",a-1);
printf("b: %d\n",b-1);
printf("c: %d\n",c);
printf("Result: %d\n",-sum);
Также оптимизированный результат: P
В любом случае, я люблю gotos!