2009-06-21 17 views
19

Project Euler numaralı sorunu çözüyorum. Benim çözümümde, iki döngüden kurtulmak için bir "goto" ifadesi kullanıyorum. Sorun şudur:İki döngüden çıkmak için goto meşru bir yol kullanıyor mu?

bir Pisagor üçlü üç doğal sayılar, bir dizi abc

Örneğin bir^2 + b^2 = C^2

, bunun için, 3^2 + 4^2 = 9 + 16 = 25 = 52 =

Tam olarak, bir + b + c = 1000 olan bir Pisagor üçlüsü vardır. Ürünü bulun abc.

Çözümümün ++ c şudur: Bu "git" makul kullanımını kabul edilip edilemeyeceğini "git" ifadeleri yana

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; 

++ programcıları c arasında çok popüler değil, ben bilmek istiyorum . Ya da "goto" gerektirmeyen problem için daha iyi bir çözüm varsa. Bununla, "goto" dan kaçınan, ama algoritmayı geliştirecek şekilde "goto" dan kaçınan bir çözüm demek istemiyorum.

+13

Kullandığınız 8-alanlı sekmeleri seviyorum .... çok seksi. –

+0

Teşekkürler, ben de onları seviyorum :-) – Lucas

+10

Ortada 16-alan bir sekme ile ... –

cevap

45

return, birçok programcının daha kabul edilebilir bulduğu "yapılandırılmış" goto'dur! Yani:

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; 
} 
+21

+1: Eğer bir gotoyu düşünecek kadar karmaşıksa, bir fonksiyonda kapsüllemek ve gotodan kaçınmak için yeterince karmaşıktır. –

+2

Yep. Döngüleri karmaşıklaştırma. Sadece dışarı çık. Mükemmel çözüm. Ama referans olarak a, b, c'yi geçebilirsin. O zaman işaretçilerle uğraşmanıza gerek yok. –

+0

Teşekkürler, bu güzel bir çözüm. Kodu daha az okunabilir yapmaz. – Lucas

4

Daha iyi bir alternatif düşünemiyorum. Ama goto kullanarak tek alternatif değildir ilk for -loop değiştirerek olacaktır: İkinci for -loop dışına

for (a = 1; a<sum && result == -1; a++){ 
Sonra

break. Bu sonuç, -loop'un break tarafından kesilmesinden sonra sonucun asla -1 olmayacağı varsayımıyla çalışacaktır. Mevcut git nerede

+2

Bunu daha iyi görmüyorum. Teste daha fazla koşul ekledikçe kodu daha zor hale getiriyorsunuz. –

+0

Ve haklısın. Dediğim gibi, daha iyi bir alternatif düşünemedim, kodu değiştirmeden goto döngüsünden kaçınmanın bir yolunu gösterdim. – Blixt

+0

Alex Martelli'nin çözümünün elbette daha iyi olduğunu eklemek isterim. Bir fonksiyonda kapsüllemek muhtemelen bu durumda en iyi çözümdür. – Blixt

4

Sen üstünde bir bool found = false olduğuna dair karar ve sonra döngü için Koşullamalar için && !found ekleyebilir ve daha sonra (a < sum ve b < sum sonra) gerçek olduğu tespit ayarlayın. Daha sonra çıkışınızın koşullu olmasının doğru olmasını sağlayın.

3

Bunu "Related" kenar çubuğunda buldum. Genel olarak ilginç bir iş parçacığı, ancak özellikle de this sorumu yanıtımdır.

6

2 döngüyü ayırma hakkında this question konusuna bakın. Goto kullanmaktan çok daha iyi cevaplar var.

Sağlanan en iyi yanıt, ikinci döngüyü bir işleve yerleştirmek ve bu işlevi ilk döngünüzün içinden çağırmaktır. Ben bu durumda goto kullanarak kedi yavruları öldürerek oldukça gibi kötü olmadığını hissediyorsunuz rağmen mquander tepki

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; 
    } 
} 

kopyalanmış

kodu. Ama yakın.

+10

Hepimizin beyni nasıl yıkadık? :) Bu kodun sonuçta oluşan yapısı, goto'yu (DoubleLoop'taki ek “if ifadesi” nedeniyle) kullanmaktan daha “karmaşık” dır. Kodun ayrılması ayrıca bir derleyicinin yapabileceği optimizasyonlar kümesini de azaltabilir - örneğin "CheckWhatever" için yerel olan bir değişken, potansiyel olarak çevreleyen döngü dışında olacak şekilde optimize edilmiş olabilir. –

+0

Goto sürümü çok daha basit. – jv110

18

Bence böyle bir durumda goto kullanmanız iyi olur.P Neyse

seviyorum:

Btw, Goto karşı küçümseyici vaaz genellikle

+1

Java, bu – Casebash

+3

@Casebash: Sure ile hemen hemen aynı olan döngülere sahiptir. Fakat bu nasıl bir cevap ya da soruyla ilgilidir? –

1
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); 

Ayrıca optimize sonuç dışarı .. .. sadece onlar başkalarının söylemek ya da bir yere okumak ne duydum papağan insanlardan geliyor gotos!

İlgili konular