Sayfalar

31 Aralık 2016

Euler Projesi 210. Soru

Geniş Açılı Üçgenler

|x| + |y| ≤ r denklemini sağlayan (x,y) tamsayı koordinatlara sahip noktalar kümesi S(r) ile gösterilsin. O(0,0) ve C(r/4,r/4) noktaları verilsin. S(r) kümesinde OBC üçgeni geniş açılı olacak şekilde alınabilen B noktalarının sayısı N(r) olsun (yani en geniş açı α, 90°<α<180° eşitsizliğini sağlar). Bu durumda, örneğin N(4)=24 ve N(8)=100 olur.

Şimdi, N(1,000,000,000) değeri kaçtır?

Cevap: 1598174770174689458

 Java:
public class Euler210 {
   Euler210(){
      final long r = 1000000000;
      long sum=0;
      
      // whole square
      sum += 2*r*(r+1)+1;
      // remove band between 0 <= x+y <=r/2
      sum -= (2*r+1)*r/4 + r+1;
      // remove points on line x=y, not in previous band
      sum -= r/2 + r/4;
      // add all points strictly interior to circle around r/8,r/8, radius r/8 sqrt2
      sum += countCircle( r*r/32 );
      // remove points on line x=y, interior to circle
      sum -= r/4 - 1;

      System.out.println(sum);
   }
   
   // count all points strictly interior to circle with squared radius r2.
   long countCircle( long r2 ){
      long x = 0;
      long x2 = 1;
      while( x2<r2 ){
         x2 += x+x+1;
         x++;
      }

      long total = 0;
      long y = 0;
      long y2next = 1;
      while( true )
      {
         x--;
         x2 -= x+x+1;
         // find top point of this column
         while( x2 + y2next < r2){
            y++;
            y2next += y+y+1;
         }
         if( x<y) break;
         total += 8*y+4;
      }
      total += (2*x+1)*(2*x+1);
      return total;
   }
}
 
C++:
#include "stdlib.h"
#include "stdio.h"
#include "math.h"
#include "string.h"


long min(a, b)
{
 return a > b ? b : a;
}

long max(a, b)
{
 return a > b ? a : b;
}

long r = 1000000000;

long okpoint(double x, double y)
{
 x -= r/8.0;
 y -= r/8.0;
 double l = sqrt(x*x+y*y);
 double m = sqrt(2.0*(r/8.0)*(r/8.0));
 
 return l < m;
}

int main(void)
{
 long total = 0;
 
 long o, a, b;
 long x, y;
 
 total += r*(2*r+1)/4;
 total -= r/4;
 
 total += r*(2*r+1)/2;
 total -= r/2;
 
 total += (r/4+1)*(r/4+1)-(r/4+1)-2;
 
 a = 0;
 b = r/4;
 y = r/4+1;
 
 long sub = 0;
 while(a < b)
 {
  while(!okpoint(a, y))
  {
   a++;
   if(a > b) break;
  }
  while(!okpoint(b, y))
  {
   b--;
   if(a > b) break;
  }
  
  if(a > b) break;
  sub += b-a+1;
  y++;
 }
 
 printf("%li\n", sub);
 
 total += sub*4;
 
 
 printf("%li\n", total);
 
 return 0;
}
 
Mathematica:
(* Compiled into C to make it run at a reasonable speed: *)
inzone2 = 
  Compile[{{n, _Integer}, {a, _Integer}, {b, _Integer}}, 
   Module[{eye = 0.0, enn = 0.0, p = 0}, enn = n; 
    Table[eye = i; p = Ceiling[Sqrt[2 enn^2 - eye^2]]; 
     2 p - 1, {i, a + 1, b}]], CompilationTarget -> "C"];

(* Counts the number of points in one quarter of the area produced by \
removing an inscribed square from the circle: *)
inzone4 = Function[{n}, Module[{q, b, x, y}, Sum[
     Print[a];
     b = Min[a + 10^6, Floor[n Sqrt[2]]];
     q = inzone2[n, a, b];
     (* Be careful with points on the circumference of the circle. 
     This deals with these cases separately, 
     since I don't trust the floating-point computations in inzone2: *)

     
     Map[(x = #[[1]]; y = #[[2]]; 
        If[a < x && x <= b, q[[x - a]] = 2 y - 1]; 
        If[a < y && y <= b, q[[y - a]] = 2 x - 1]) &, 
      PowersRepresentations[2 n^2, 2, 2]];
     Total[q]
     (* Split it into chunks of 10^6 to avoid using ridiculous \
swathes of memory: *)
     , {a, n, Floor[n Sqrt[2]], 10^6}]]];

(* Gives the number of points in the interior of a circle of radius n \
Sqrt[2]: *)
interior = Function[{n}, 4 inzone4[n] + (2 n + 1)^2 - 4];

(* Gives the number of obtuse-angled triangles: *)
obtuse = Function[{r}, interior[r/8] + 3 r^2/2 - (r/4 - 1)];

(* Actually do the computation: *)
AbsoluteTiming[obtuse[10^9]]
 
Vb:
Public Shared Function Problem210() As String
  Const r = 1000L * 1000 * 1000
  Const d = r \ 4
  Dim total = 0L, innertotal = 0L
  total += (r + 1) * (r + 1) + r * r  '' add all points
  total -= (d + 1) * (r + 1) + d * r  '' remove points internal to (1,-1)-(-1,1) and (d,0)-(0,-d)
  total -= (r - d) '' remove outer colinear non-triangle points

  Dim radiussquare = r * r \ 32
  Dim radius = Math.Sqrt(radiussquare)
  Dim maxwidth = CLng(radius)
  For height = 1 To CLng(Math.Floor(radius))
    Do While maxwidth * maxwidth + height * height >= radiussquare AndAlso maxwidth > 0
      maxwidth -= 1
    Loop
    innertotal += CInt(Math.Floor(maxwidth)) + 1
  Next
  innertotal *= 4   '' we calculated only a quarter of the circle
  innertotal -= (r \ 4) - 2 '' remove inner colinear points, except those ignored in center, at O and at C
  total += innertotal
  Return total.ToString()
End Function
 
c#:
class Task210:Task
    {
        const long r = 1000000000;
        const long r2 = r / 2;
        public override void doTask()
        {
            //BruteForce();
     long sum = 3 * r * r2+N(r)-r/4+((r%8==0)?1:0);
            Print(sum.ToString());
        }

        private long N(long R)
        {
            double Ox = R / 8.0;
            long Oy = (long)Math.Ceiling(R / 8.0);
            long count = 0;
            long y = Oy;
            for (long x = (long)((1.0+Math.Sqrt(2))/8.0*R); x > Ox; --x)
            {
                while ((8*x-R) * (8*x-R) + (8*y-R) * (8*y-R) < 2* R * R) ++y;
                count += (y-Oy);
            }

            return 4 * count + 1;
        }

        private void BruteForce()
        {
            int x0 = 0;
            int y0 = 0;
            int xC = (int)r / 4;
            int yC = (int)r / 4;

            ulong count = 0;

            for (long xB = -r; xB <= r; ++xB)
            {
                long yMin = (xB > 0) ? xB - r : -xB - r;
                long yMax = (xB > 0) ? -xB + r : xB + r;

                for (long yB = yMin; yB <= yMax; ++yB)
                {
                    if (isObtuse(x0 - xC, y0 - yC, xB - xC, yB - yC) ||
                        isObtuse(x0 - xB, y0 - yB, xC - xB, yC - yB) ||
                        isObtuse(xB - x0, yB - y0, xC - x0, yC - y0))
                    {
                        ++count;
                        Print(xB.ToString() + "," + yB.ToString() + ",true");
                    }
                }

            }

            Print(DateTime.Now.ToString() + ": " + count.ToString());
        }

        private bool isObtuse(long x1, long y1, long x2, long y2)
        {
            long dotProduct = x1 * x2 + y1 * y2;
            long lenProduct = (x1*x1+y1*y1)*(x2*x2+y2*y2);
            return (dotProduct < 0 && dotProduct*dotProduct < lenProduct);
        }
}