{"id":614,"date":"2008-12-08T12:23:37","date_gmt":"2008-12-08T11:23:37","guid":{"rendered":"http:\/\/www.navision-blog.de\/2008\/12\/08\/project-euler-in-fsharp-problem-53\/"},"modified":"2009-01-13T09:01:17","modified_gmt":"2009-01-13T08:01:17","slug":"project-euler-in-fsharp-problem-53","status":"publish","type":"post","link":"http:\/\/www.navision-blog.de\/blog\/2008\/12\/08\/project-euler-in-fsharp-problem-53\/","title":{"rendered":"Project Euler in F# &#8211; Problem 53 &#8211; Dynamic Programming"},"content":{"rendered":"<p>Claudio Cherubino (from <a href=\"http:\/\/www.fsharp.it\/\">fsharp.it\/<\/a>) posted <a href=\"http:\/\/www.fsharp.it\/2008\/12\/07\/project-euler-in-f-problem-53\/\">his solution<\/a> to <a href=\"http:\/\/projecteuler.net\/index.php?section=problems&amp;id=53\">Euler Project &#8211; problem 53<\/a>. As I dealed a lot with <a href=\"http:\/\/en.wikipedia.org\/wiki\/Dynamic_programming\">Dynamic Programming<\/a> in the recent time, I tried to solve the problem with a dynamic program in F#.<\/p>\n<p><strong><\/strong><\/p>\n<blockquote><p><a href=\"http:\/\/projecteuler.net\/index.php?section=problems&amp;id=53\">Project Euler &#8211; Problem 53:<\/a><\/p>\n<p>How many values of C(<em>n<\/em>,<em>k<\/em>), for 1 \u2264 <em>n<\/em> \u2264 100, exceed one-million?<\/p>\n<p>Remark: C(n,k) are the binomial coefficients.<\/p><\/blockquote>\n<p>As it turned out, this is not that complicated if one knows the recursive function for the binomial coefficients (see <a href=\"http:\/\/en.wikipedia.org\/wiki\/Binomial_coefficient\">Wikipedia<\/a>):<\/p>\n<p><img loading=\"lazy\" style=\"border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px\" src=\"http:\/\/www.navision-blog.de\/images\/ProjectEulerinFProblem53_AC8B\/image.png\" border=\"0\" alt=\"Recursive definition for the Binomial coefficient\" width=\"226\" height=\"51\" \/> with <img loading=\"lazy\" style=\"border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px\" src=\"http:\/\/www.navision-blog.de\/images\/ProjectEulerinFProblem53_AC8B\/image_3.png\" border=\"0\" alt=\"Recursive definition for the Binomial coefficient\" width=\"147\" height=\"53\" \/><\/p>\n<p>This is easily transformed into a F# program:<\/p>\n<pre class=\"code\"><span style=\"color: blue;\">let <\/span>binomials = Array2.create 101 101 1I\r\n<span style=\"color: blue;\">let <\/span>answer = ref 0\r\n<span style=\"color: blue;\">for <\/span>n <span style=\"color: blue;\">in <\/span>[1..100] <span style=\"color: blue;\">do\r\n  for <\/span>k <span style=\"color: blue;\">in <\/span>[1..n - 1] <span style=\"color: blue;\">do\r\n    <\/span>binomials.[n, k] &lt;- binomials.[n - 1,k] + binomials.[n - 1,k - 1]\r\n    <span style=\"color: blue;\">if <\/span>binomials.[n, k] &gt; 1000000I <span style=\"color: blue;\">then\r\n      <\/span>answer := !answer + 1\r\n\r\n!answer |&gt; printf <span style=\"color: maroon;\">\"Answer: %A\"<\/span><\/pre>\n<p>Claudio&#8217;s program took 1315ms on my computer. The dynamic program needs only 63ms. But we can still do better if we use the symmetry of <a href=\"http:\/\/en.wikipedia.org\/wiki\/Pascal%27s_triangle\">Pascal&#8217;s triangle<\/a>.<\/p>\n<p><img loading=\"lazy\" style=\"border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px\" src=\"http:\/\/www.navision-blog.de\/images\/ProjectEulerinFProblem53_AC8B\/image_4.png\" border=\"0\" alt=\"Symmetry of Pascal's triangle\" width=\"95\" height=\"28\" \/><\/p>\n<p>This leads to an algorithm, which calculates only half of the binomial coefficients.<\/p>\n<pre class=\"code\"><span style=\"color: blue;\">let <\/span>binomials = Array2.create 101 101 1I\r\n<span style=\"color: blue;\">let <\/span>answer = ref 0\r\n<span style=\"color: blue;\">for <\/span>n <span style=\"color: blue;\">in <\/span>[1..100] <span style=\"color: blue;\">do\r\n  for <\/span>k <span style=\"color: blue;\">in <\/span>[1..n\/2] <span style=\"color: blue;\">do\r\n    let <\/span>b = binomials.[n - 1,k] + binomials.[n - 1,k - 1]\r\n    binomials.[n, k] &lt;- b\r\n    binomials.[n, n - k] &lt;- b\r\n    <span style=\"color: blue;\">if <\/span>b &gt; 1000000I <span style=\"color: blue;\">then\r\n      if <\/span>k = n-k <span style=\"color: blue;\">then\r\n        <\/span>answer := !answer + 1\r\n      <span style=\"color: blue;\">else\r\n        <\/span>answer := !answer + 2<\/pre>\n<pre class=\"code\">!answer |&gt; printf <span style=\"color: maroon;\">\"Answer: %A\"<\/span><\/pre>\n<p>This version needs only 45ms &#8211; but we are not ready. I mentioned Pascal&#8217;s triangle and its symmetry. But we can use another property. We don&#8217;t have to calculate the complete row, if we exceed 100000. All values behind this threshold have to be greater.<\/p>\n<pre class=\"code\"><span style=\"color: blue;\">let <\/span>binomials = Array2.create 101 101 1I\r\n<span style=\"color: blue;\">let <\/span>answer = ref 0\r\n<span style=\"color: blue;\">for <\/span>n <span style=\"color: blue;\">in <\/span>[1..100] <span style=\"color: blue;\">do\r\n  let <\/span>threshold_reached = ref <span style=\"color: blue;\">false\r\n  let <\/span>c = ref 0\r\n  <span style=\"color: blue;\">for <\/span>k <span style=\"color: blue;\">in <\/span>[1..n\/2] <span style=\"color: blue;\">do\r\n    if <\/span>not !threshold_reached <span style=\"color: blue;\">then\r\n      let <\/span>b = binomials.[n - 1,k] + binomials.[n - 1,k - 1]\r\n      binomials.[n, k] &lt;- b\r\n      binomials.[n, n - k] &lt;- b\r\n      <span style=\"color: blue;\">if <\/span>b &gt; 1000000I <span style=\"color: blue;\">then\r\n        <\/span>threshold_reached := <span style=\"color: blue;\">true\r\n      else\r\n        <\/span>c := !c + 1\r\n\r\n  <span style=\"color: blue;\">if <\/span>!threshold_reached <span style=\"color: blue;\">then\r\n    <\/span>answer := !answer + (n - 1) - (2 * !c)<\/pre>\n<pre class=\"code\">!answer |&gt; printf <span style=\"color: maroon;\">\"Answer: %A\"<\/span><\/pre>\n<p>This final version took only 29 ms.<\/p>\n<p>In the <a href=\"http:\/\/www.navision-blog.de\/2008\/12\/08\/project-euler-in-f-problem-53-memoization\/\">next posting<\/a> I will show a version using memoization.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Claudio Cherubino (from fsharp.it\/) posted his solution to Euler Project &#8211; problem 53. As I dealed a lot with Dynamic Programming in the recent time, I tried to solve the problem with a dynamic program in F#. Project Euler &#8211; Problem 53: How many values of C(n,k), for 1 \u2264 n \u2264 100, exceed one-million? [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[23,448,10],"tags":[488,485,664,487,486],"_links":{"self":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/614"}],"collection":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/comments?post=614"}],"version-history":[{"count":6,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/614\/revisions"}],"predecessor-version":[{"id":661,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/614\/revisions\/661"}],"wp:attachment":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=614"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=614"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=614"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}