-3

Project Eulerの問題2を解決しようとしています。問題は:

「フィボナッチ数列の各新しい項は、前の 2 つの項を追加することによって生成されます。1 と 2 から始めると、最初の 10 項は次のようになります。

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

値が 400 万を超えないフィボナッチ数列の項を考慮して、偶数値の項の合計を見つけます。」

これをC++で解決しようとしています。

これまでの私のコードは次のとおりです

#include <iostream>
 using namespace std;

int main()
{
    //ANSWER = 4613732
    int max = 4000000;
    int n;
    int sum;

    for(n=0; n<=max;)
    {
        while(n%2 == 0)
        {
            n = (n-1)+(n-2);
        }
    }
    sum = n+=0;
    cout << sum << endl;
    return 0;
}

ご覧のとおり、自分の答えを確認するために検索して正しい答えを知っています。私が持っているこのコードは永遠に実行され、決して答えを示しません。この答えにたどり着き、私のC++コードを改善する方法についてのヒントを教えてください。前もって感謝します!

4

4 に答える 4

5

これがあなたが従うべきではないアプローチです。(注:この投稿は冗談ですが、私はこのアプローチに従わないことを真剣に考えています。C++の理解レベルでこのアプローチを理解しようとすることもお勧めできません。)

#include <iostream>

struct Fib
{
  template<int n, int first=1, int second=1> struct Eval { enum {value = Eval<n-1, first, second>::value + Eval<n-2, first, second>::value}; };
  template<int first, int second> struct Eval<1, first, second> { enum {value = second}; };
  template<int first, int second> struct Eval<0, first, second> { enum {value = first}; };

};
struct SpecificFib
{
  template<int n> struct Eval { enum{ value = Fib::template Eval<n, 1, 2>::value }; };
};

template<int... values> struct Sequence {};
template<typename Seq, int n> struct Append;
template<int... values, int n> struct Append<Sequence<values...>, n> { typedef Sequence<values...,n> type; };
template<typename Seq, int n> struct Prepend;
template<int... values, int n> struct Prepend<Sequence<values...>, n> { typedef Sequence<n, values...> type; };

template<typename Func,typename Seq,typename Test=void> struct Filter;

template<typename Func,int first, int... values>
struct Filter<Func,Sequence<first,values...>,typename std::enable_if< Func::template Eval<first>::value>::type>
{
  typedef typename Prepend<typename Filter<Func,Sequence<values...>>::type,first>::type type;
};

template<typename Func,int first, int... values>
struct Filter<Func,Sequence<first,values...>,typename std::enable_if< !Func::template Eval<first>::value>::type>
{
  typedef typename Filter<Func,Sequence<values...>>::type type;
};
template<typename Func> struct Filter<Func,Sequence<>> { typedef Sequence<> type; };

struct IsEven {
  template<int n> struct Eval { enum{ value = !(n%2) }; };
};

template<typename Func,typename Seq> struct Map;
template<typename Func,int first, int... values>
struct Map<Func, Sequence<first,values...>>
{
  typedef Sequence<values...> Tail;
  typedef typename Map<Func,Tail>::type TailMapped;
  enum { firstMapped = Func::template Eval<first>::value };

  typedef typename Prepend<TailMapped,firstMapped>::type type;
};
template<typename Func>
struct Map<Func,Sequence<>>
{
  typedef Sequence<> type;
};

template<int begin, int end>
struct generate_sequence
{
  template<int current, int... values>
  struct helper: helper<current-1, current-1, values...> {};
  template<int... values>
  struct helper<begin, values...>
  {
    typedef Sequence<values...> type;
  };
  typedef typename helper<end>::type type;
};
template<typename Seq> struct Sum;
template<int first, int... values> struct Sum<Sequence<first, values...>> { enum {value = first + Sum<Sequence<values...>>::value}; };
template<> struct Sum<Sequence<>> { enum {value = 0}; };

template<typename Seq1, typename Seq2=Sequence<>>
struct Reverse { typedef Seq2 type; };

template<int first, int... values, typename Seq2>
struct Reverse<Sequence<first,values...>, Seq2>:Reverse<Sequence<values...>, typename Prepend<Seq2,first>::type> {};

template<typename Seq, char sep=','> struct PrintHelper;
template<int first, int second, int... values, char sep> struct PrintHelper<Sequence<first,second,values...>, sep>:PrintHelper<Sequence<second,values...>, sep>
{
  PrintHelper() { std::cout << sep << first; }
};
template<int last, char sep> struct PrintHelper<Sequence<last>, sep>:PrintHelper<Sequence<>, sep>
{
  PrintHelper() { std::cout << last; }
};
template<char sep> struct PrintHelper<Sequence<>,sep> { PrintHelper() {} void Do() const {} };
template<typename Seq, char sep=','> struct Print: PrintHelper< typename Reverse<Seq>::type, sep >
{};

typedef typename generate_sequence<0, 10>::type ZeroTo9;
typedef typename Map<SpecificFib,ZeroTo9>::type First10Fibs;
typedef typename Filter<IsEven,First10Fibs>::type First10FibsThatAreEven;

template<typename Sequence>
void PrintSomeInfo( std::string const& name )
{
  std::cout << name << " {";
  Print<Sequence>();
  std::cout << "} sums to " << Sum<Sequence>::value << "\n";
}
int main()
{
  PrintSomeInfo<ZeroTo9>("Zero to 9");
  PrintSomeInfo<First10Fibs>("First 10 fibs");
  PrintSomeInfo<First10FibsThatAreEven>("First 10 fibs that are even");
}

それがお役に立てば幸いです。

私が上でやっていることは、テンプレートプログラミングで遊んでいることです。私は、コンパイラが適切にコンパイルされた場合Sum<Sequence>::value、それが単一のコンパイル時の値になるように、かなり強力なC++型システムを使用して答えを推測しています。

技術的には、これはC++で書かれた質問に対する答えです。ボーナスとして、O(1)実行時間があります。:)

..。

もっと真剣に。一度に1ステップずつ問題を解決する必要があります。

シーケンスの最初の10個の要素を出力するプログラムを作成します。私は「上記のように」と言いますが、あなたはあなたが理解する方法でそれをするべきです。

于 2012-11-27T03:48:20.547 に答える
2

コードを段階的に分析して、どこが間違っているかを見てみましょう。

    //ANSWER = 4613732
    int max = 4000000;
    int n;
    int sum;

    for(n=0; n<=max;)
    {

ここでやめましょう... このループは何をするのでしょうか? 0 から始まり、n が 4000001 になるまでループします。問題の説明では、4000000 を超えない偶数のフィボナッチ項を合計するように求められます。したがって、基本的に、nフィボナッチ数を格納する変数として扱っています。わかった...

        while(n%2 == 0)
        {

では、このコードは何をするのでしょうか? 偶数の間ループしますn。なぜそれをしたいのですか?

            n = (n-1)+(n-2);

わかった。では、これは何を計算するのでしょうか?ちょっと、フィボナッチ数を計算するもののように見えます。しかし、そうですか?確認しよう!から始めn = 0ます。0 % 2 == 0このコードを実行すると、n が (0 - 1) + (0 - 2) = 0 - 1 + 0 - 2 = -3 に設定されることに注意してください。-3 は偶数ではないため、ループは終了します。

しかし... 待ってください、-3 はフィボナッチ数ではありません!

フィボナッチ数 (F(n) と呼びましょう) は次の式で定義されることを思い出してください: F(n) = F(n - 1) + F(n - 2)、F(0) = 0 の特殊なケースF(1) = 1. つまり、フィボナッチ数は前の 2 つのフィボナッチ数の合計です。

さて、あなたが書いた式はフィボナッチ数を計算しますか?

ところで、この時点で、このコードが実行され、実行され、実行され、実行される理由を確認できるはずです...そうでない場合は、何が何であるかを思い出して、ループnを確認してください。for何が起こるか?

私はあなたに答えを与えるつもりです。少し複雑すぎるかもしれませんが、時間をかけてに書いてコンピュータのように作業し、各ステップを 1 行ずつ追っていくと、どのように機能するかがわかり、C と C++ をよりよく理解できるようになります。アルゴリズムと数学的概念をコードに変換する方法。

#include <iostream>
using namespace std;


int main(int argc, char **argv)
{           
    // We store the last 2 Fibonacci numbers that we calculated in this 
    // small array to improve the performance of our routine and avoid
    // having to recalculate things all the time. We update it as we go
    // and initialize it with the values for fib(0) and fib(1)

    int max = 4000000, ans = 4613732, sum = 0, lfi = 0, lfn = 1;
    int lastfibs[2] = { 0, 1 }; 

    do  
    {
        // Calculate the next fibonacci number in the sequence
        lfn = lastfibs[0] + lastfibs[1];

        // And store it in our cache, updating the cache index
        lastfibs[lfi++] = lfn;

        if(lfi == 2) // "round and round you're turning me..."
            lfi = 0;                

        if((lfn & 1) == 0) // An even Fibonacci number! Add it to the sum
            sum += lfn;
    } while(lfn <= max);

    if(sum != ans)
        cout << "BOO! The sum is " << sum << " but it's supposed to be " << ans << "!" << endl;
    else
        cout << "Yay! The sum is " << sum << "! Thanks StackOverflow!" << endl;

    return 0;
}

問題について考え、独自の解決策を考え出すのに役立つこと を願っています。

于 2012-11-27T03:05:22.423 に答える