Использует 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!