Archive for February, 2012

Project Euler Problem #91!

February 11th, 2012

Problem #91 says

The points \(P (x_1, y_1)\) and \(Q (x_2, y_2)\) are plotted at integer co-ordinates and are joined to the origin, \(O(0,0)\), to form \(ΔOPQ\).
There are exactly fourteen triangles containing a right angle that can be formed when each co-ordinate lies between 0 and 2 inclusive; that is,
\( 0 \leq x_1, y_1, x_2, y_2 \leq 2 \).
Given that \( 0 \leq x_1, y_1, x_2, y_2 \leq 50 \), how many right triangles can be formed?

A good way to tackle this problem is with good old Pythagoras’s equation. \(a^2 + b^2 = c^2\) but we need to avoid floating point operations which might screw up our results! The best way to do this is to avoid taking square roots because we know all of our points are located on integral spots on the grid. So we create little triangle objects that hold the origin and the two other points and we check the Pythagoras equation and if it passes we add it to our collection after checking for duplicates. Simply iterate through all of the points and count the triangles in out collection to get our answer.

So somethings that could be changed to make it faster. This solution creates a lot of objects and doesn’t really need them; this whole program could be rewritten to run without the OriginTri and Point classes but it’s easier to think about with them in my opinion. Removing the object creation however could shave quite a bit off of the run time. Solution in c# and runs in 13 seconds or so on my machine.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace Problem91
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            OriginTri testcase;
            HashSet<string> triangles = new HashSet<string>();
            int max = 50;
            int count = 0;
            for (int x1 = 0; x1 <= max; x1++)
            {
                for (int y1 = 0; y1 <= max; y1++)
                {
                    for (int x2 = 0; x2 <= max; x2++)
                    {
                        for (int y2 = 0; y2 <= max; y2++)
                        {
                            testcase = new OriginTri(new Point(x1, y1), new Point(x2, y2));
                            if (testcase.IsRightTri() && !triangles.Contains(testcase.ToString()))
                            {
                                count++;
                                triangles.Add(testcase.ToString());
                                triangles.Add((new OriginTri(new Point(x2, y2), new Point(x1, y1))).ToString());
                            }
                        }
                    }
                }
            }
            sw.Stop();
            Console.WriteLine(count);
            Console.WriteLine(sw.Elapsed);
            Console.ReadLine();
        }
    }
    class OriginTri
    {
        Point origin = new Point(0,0);
        Point p1;
        Point p2;
        public OriginTri(Point p, Point q)
        {
            p1 = p;
            p2 = q;
        }
        public bool IsRightTri()
        {
            if (p1.ToString() == p2.ToString())
                return false;
            if (p1.ToString() == origin.ToString() || p2.ToString() == origin.ToString())
                return false;
        
            int S1 = p1.SquaredDistToPoint(origin);
            int S2 = p2.SquaredDistToPoint(origin);
            int S3 = p1.SquaredDistToPoint(p2);

            if (S1 + S2 == S3)
                return true;
            if (S2 + S3 == S1)
                return true;
            if (S3 + S1 == S2)
                return true;
            return false;
        }
        public override string ToString()
        {
            if (p1.MagFromZero() < p2.MagFromZero())   
                return "(0,0)" + p1.ToString() + p2.ToString();
            if (p1.MagFromZero() >= p2.MagFromZero())
                return "(0,0)" + p2.ToString() + p1.ToString();
            return "error";
        }
    }
    class Point
    {
        public int X;
        public int Y;
        public Point(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
        public int SquaredDistToPoint(Point p)
        {
            int tmpy = p.Y - this.Y;
            int tmpx = p.X - this.X;

            return (tmpx * tmpx) + (tmpy * tmpy);
        }
        public double MagFromZero()
        {
            return Math.Sqrt((double)(X * X) + (double)(Y * Y));
        }
        public override string ToString()
        {
            return "(" + X.ToString() + "," + Y.ToString() + ")";
        }
    }
}

Tags: , ,
Posted in Project Euler | Comments (0)