2010-09-27 15 views
8

मैं 500 divisors के साथ पहले त्रिकोण संख्या के बारे में समस्या 12 पर काम कर रहा हूँ। मैंने समाधान को मजबूर करने की कोशिश की। मुझे लगभग 35 सेकंड में 300 divisors मिलते हैं और 10 मिनट के भीतर 400 नहीं मिल सकता है। मैं प्राइम फैक्टर विधि का उपयोग करने के लिए अपने समाधान को बदलने जा रहा हूं लेकिन मैंने अब देखा है कि लोग अभी भी एक मिनट के भीतर ब्रूट फोर्स के साथ इस समाधान को प्राप्त कर रहे हैं।प्रोजेक्ट यूलर समस्या 12 - सी ++

क्या आप कृपया मेरे कोड की आलोचना कर सकते हैं और मुझे बता सकते हैं कि क्या मुझे ऐसा कुछ याद आ रहा है जो इस बेहद अक्षम है?

unsigned long long TriangleNumberDivisors(int divisorTarget) 
{ 
    unsigned long long triangleNum=1; 
     unsigned long long currentNum=2; 
    int numOfDivisors=0; 


    numOfDivisors=NumOfDivisors(triangleNum); 
    while(numOfDivisors<divisorTarget) 
    { 
     triangleNum+=currentNum; 
     currentNum++; 
     numOfDivisors=NumOfDivisors(triangleNum); 
    } 

    return triangleNum; 
} 

int NumOfDivisors(unsigned long long dividend) 
{ 
    int numDivisors=0; 
    set<unsigned long long> divisors; 
    set<unsigned long long>::iterator it; 

    for(unsigned long long index=1; index<=dividend/2; index++) 
    { 
     if(dividend%index==0) 
     { 
      divisors.insert(index); 
      numDivisors++; 
      it=divisors.find(dividend/index); 
      if(it==divisors.end()) 
      { 
       divisors.insert(dividend/index); 
       numDivisors++; 
      } 
       /*for some reason not checking for dups above and 
just checking for how many items are in the set at the end is slower 
      for(it=divisors.begin();it!=divisors.end();it++) 
      { 
        numDivisors++; 
      } 
        */ 
     } 
    } 

    return numDivisors; 
} 

int main() 
{ 
    cout<<TriangleNumberDivisors(500)<<endl; 

    return 0; 
} 

अद्यतन: अब इसे प्राप्त करें, धन्यवाद। संख्या के वर्ग रूट की जांच करने के लिए बदल दिया गया, और यह देखने के लिए एक अतिरिक्त जांच की गई कि यह एक आदर्श वर्ग था या नहीं। इसने मुझे सेट को पूरी तरह से हटाने की अनुमति दी। 500 divisors 12 सेकंड में भाग गया।

+6

कृपया '=', '<', '==' के आस-पास की जगहें रखें; otherwiseitisverydifficulttoread। – Arun

+1

कृपया एक ही प्रश्न के लिए मेरा उत्तर पढ़ें: http://stackoverflow.com/questions/3273379/understanding-some-math-relating-to-euler-12/3273405#3273405 :) – AraK

उत्तर

10

वर्तमान में आप dividend/2 तक विभाजक की जांच करते हैं। आप इसे sqrt(dividend) पर कम कर सकते हैं, जो असम्बद्ध रूप से तेज़ है। dividend वर्ग है तो एक विशेष मामले की आवश्यकता हो सकती है।

मेरे सी ++ समस्या 12 के लिए कोड (जो अनिवार्य रूप से तुम्हारा के रूप में ही है, लेकिन यह कम सीमा का उपयोग करता है, और यह भी सिर्फ उन्हें सेट में भंडारण के बजाय divisors में गिना जाता है) लेता है के बारे में 1 सेकंड

+0

मुझे समझ में नहीं आता क्यों divisors की जांच sqrt (लाभांश) के लिए काम करेगा। उदाहरण के लिए, 28 के विभाजक 1,2,4,7,14,28 हैं। sqrt (28) 5 है। यदि आप 5 पर जांच करना बंद कर देते हैं तो आप 7 और 14 कैसे पा सकते हैं? –

+1

@ जेरोम डिवीजन जोड़े में आते हैं (जब आपको विभाजक 2 मिलते हैं, तो आप भी विभाजक 14 को पाते हैं; जब आपको 4 मिलते हैं, तो आप निश्चित रूप से 7 पाते हैं)। इसलिए आप स्क्वायर रूट से कम प्रत्येक divisors के लिए दो divisors गिन सकते हैं। –

4
for(unsigned long long index=1; index<=dividend/2; index++) 

मैं देखें कि आपने अपने लूप को dividend/2 पर dividend पर पुन: स्थापित करने के बजाय इसे अनुकूलित करने का प्रयास किया है। अपने आप को sqrt(dividend) तक सीमित करना बेहतर होगा (इस अर्थ में कि आप कम divisors की जांच कर रहे हैं)।

प्लस, यदि आप लाभांश के वर्ग रूट द्वारा स्वयं को सीमित करते हैं, तो आपको डुप्लिकेट डिवीजनों की जांच करने की आवश्यकता नहीं है। यह केवल वर्ग संख्याओं के लिए होगा, इसलिए डुप्लिकेट डालने से बचने के लिए केवल अनुक्रमणिका == लाभांश/अनुक्रमणिका जांचें।

+1

थोड़ा सुधार: परीक्षण के बजाय 'इंडेक्स == लाभांश/सूचकांक' यह जांचने के लिए तेज़ हो सकता है कि 'इंडेक्स * इंडेक्स == लाभांश', गुणा के रूप में आमतौर पर विभाजन से तेज है। – LarsH

+0

मुझे लगता है कि आप का मतलब है कि sqrt (लाभांश) को प्रतिस्थापित करने के लिए। अगर हम लूप के प्रत्येक पुनरावृत्ति के लिए वर्ग रूट की गणना करते हैं तो यह काम करेगा। हालांकि, आप आदर्श रूप से एक बार sqrt की गणना करेंगे, इसे सहेजें और फिर 'अनुक्रमणिका <= saved_sqrt' देखें, जो कि बस दो संख्याओं की तुलना कर रहा है। प्रत्येक पुनरावृत्ति के लिए 'sqrt' को पुन: गणना करने की आवश्यकता नहीं है, क्योंकि यह नहीं बदलेगा (लेकिन प्रत्येक सूचकांक में' अनुक्रमणिका 'का वर्ग बदलता है)। – Tim

2

मुझे यकीन नहीं है कि आपको divisors, set टाइप वैरिएबल, NumOfDivisors विधि में क्यों चाहिए। numDivisors क्यों गिनती है (sqrt(dividend) तक इंडेक्स के साथ) पर्याप्त नहीं है? (set एक संतुलित बाइनरी खोज पेड़ के रूप में लागू किया गया है, यह विधि को धीमा कर रहा है।)। इसके अलावा, ऐसा लगता है कि आप divisors.insert(..)दो बार का आह्वान कर रहे हैं।

1

ऐसा लगता है कि आप कुछ प्रदर्शन प्राप्त कर सकते हैं यदि आपने किसी विशेष संख्या के लिए विभाजक की संख्या को कैश किया था।

संबंधित मुद्दे