• Project Euler 91:Right triangles with integer coordinates 格点直角三角形


    Right triangles with integer coordinates

    The points P (x1, y1) and Q (x2, y2) 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 ≤ x1, y1, x2, y2 ≤ 2.

    Given that 0 ≤ x1, y1, x2, y2 ≤ 50, how many right triangles can be formed?


    格点直角三角形

    点P(x1, y1)和点Q(x2, y2)都是格点,并与原点O(0,0)构成ΔOPQ。

    当点P和点Q的所有坐标都在0到2之间,也就是说0 ≤ x1, y1, x2, y2 ≤ 2时,恰好能构造出14个直角三角形。

    如果0 ≤ x1, y1, x2, y2 ≤ 50,能构造出多少个直角三角形?

     解题

     先网上找到的答案,然后看题解中,前面几题给出了暴露的方法,遍历所有的点 ,判断是否是直角三角形就好了,最后的结果要除以2,,因为两个点是可以互换的。

    Java

    package Level3;
    
    public class PE091{
        static void run(){
            int N = 50;
            int count = 0;
            // 第一个顶点
            for(int x1 = 0; x1<=N;x1++){
                for(int y1 = 0;y1<=N ;y1++){
                    if(x1==0 && y1==0) continue;
                    // 第二个顶点
                    for(int x2 = 0;x2<=N;x2++){
                        for(int y2=0;y2<=N;y2++){
                            if(x2==0&&y2==0 || x1==x2&&y1==y2)
                                continue;
                            //判断是否是三角形
                            double d1 = getDistance(0,0,x1,y1);
                            double d2 = getDistance(0,0,x2,y2);
                            double d3 = getDistance(x1,y1,x2,y2);
                            if(d1+d2==d3|| d1+d3==d2||d2+d3==d1)
                                count++;
                        }
                    }
                }
            }
            System.out.println(count/2);
        }
    //    14234
    //    running time=0s71ms
        static double getDistance(int x1,int y1,int x2,int y2){
            double d1 = (x1-x2)*(x1-x2);
            double d2 = (y1-y2)*(y1-y2);
            return d1+d2;
        }
        
        public static void main(String[] args) {
            long t0 = System.currentTimeMillis();
            run();
            long t1 = System.currentTimeMillis();
            long t = t1 - t0;
            System.out.println("running time="+t/1000+"s"+t%1000+"ms");
    
        }
    }

    参考链接1  参考链接2 

    上面给出来很好的不用暴力的方法

    对于直角在原点的情况:

    P Q两点只能在x轴  y轴上,固定一点看另一点,显然有50中可能,然而这一点也有50种可能,共2500种

    对于直角在x轴或者y轴的情况:

    当P 在x轴上的某点时候,Q的x坐标显然要和P 的一样,PQ都各有50个位置,共2500种

    当P 在y轴的时候,也有2500种

    对于直角在方格内部的时候:

    要使得是直角三角形:OP要垂直PQ

    OP的斜率:k = dy/dx  (dy/dx是最简分数)    其中P的坐标设为(x,y)

    则PQ的斜率是:-dx/dy

    如何根据斜率,找到Q的整数点,或者Q点的个数。

    当P点的y轴值>Q点的y轴的值时候:

    (如上图所示)可以发现:Q1 Q2 把PQ3等分成三份。三个Q点都是整数点。

    对斜率为k = dy/dx :可以通过一个dy * dx的方格表示出来,所以,对于P(x,y)点,x每加一个dx y每减一个dy都是一个整数Q点,那么有多少个符合要求的点?只需要看最大能走多少步,

    对于PQ的斜率是dx/dy,当P(x,y),   对x而言最大的步数是:(N-x)/dy ,对y而言最大的步数是:y/dx

    这样其最小值就是Q的整数点数:MIN((N-x)/dy,y/dx)

    当P点的y轴值<Q点的y轴的值时候:


    PQ的斜率是:-dx/dy 

    P(x,y) x向左走的最大步数:x/dy y向上走的最大步数:(N-y)/dx

    这样其最小值就是Q的整数点数:MIN(x/dy,(N-y)/dx)

    这与上面链接的结果不一样,根据运行结果发现答案是一样的

    其实吧 对于P点的坐标可以是在N*N方格中的任意一点,P的坐标是可以对称的,所以可以直接乘以二的。

    JAVA

    package Level3;
    
    public class PE091{
        static void run1(){
            int N = 50;
            // 直角在原点,直角在x轴 直角在y轴,个数都是N*N
            int result =N*N*3;
            //下面只需要对直角在方格内部的情况
            for(int x = 1;x<= N;x++){
                for(int y=1;y<= N;y++){
                    int fact = gcd(x,y);
                    result += Math.min(y*fact/x, (N-x)*fact/y);
                    result += Math.min(x*fact/y, (N-y)*fact/x);
                }
            }
            System.out.println(result);
        }
    //    14234
    //    running time=0s78ms
        static int gcd(int x,int y){
            if(x<y){
                int tmp = x;
                x = y;
                y = tmp;
            }
            int r = x%y;
            while(r!=0){
                int tmp =x;
                x = y;
                y = tmp%x;
                r = x%y;
            }
            return y;
        }
        static void run(){
            int N = 50;
            int count = 0;
            // 第一个顶点
            for(int x1 = 0; x1<=N;x1++){
                for(int y1 = 0;y1<=N ;y1++){
                    if(x1==0 && y1==0) continue;
                    // 第二个顶点
                    for(int x2 = 0;x2<=N;x2++){
                        for(int y2=0;y2<=N;y2++){
                            if(x2==0&&y2==0 || x1==x2&&y1==y2)
                                continue;
                            //判断是否是三角形
                            double d1 = getDistance(0,0,x1,y1);
                            double d2 = getDistance(0,0,x2,y2);
                            double d3 = getDistance(x1,y1,x2,y2);
                            if(d1+d2==d3|| d1+d3==d2||d2+d3==d1)
                                count++;
                        }
                    }
                }
            }
            System.out.println(count/2);
        }
    //    14234
    //    running time=0s71ms
        static double getDistance(int x1,int y1,int x2,int y2){
            double d1 = (x1-x2)*(x1-x2);
            double d2 = (y1-y2)*(y1-y2);
            return d1+d2;
        }
        
        public static void main(String[] args) {
            long t0 = System.currentTimeMillis();
            run();
            long t1 = System.currentTimeMillis();
            long t = t1 - t0;
            System.out.println("running time="+t/1000+"s"+t%1000+"ms");
    
        }
    }

     Python

    # coding=gbk
    
    import time as time 
    from itertools import combinations  
    def run():
        N = 50 
        count  = N*N*3
        for x in range(1,N+1):
            for y in range(1,N+1):
                fact = gcd(x,y)
                count += min((N-x)*fact/y,y*fact/x)*2 
        print count 
                
    # 14234
    # running time= 0.00300002098083 s   
    def gcd(x,y):
        if x<y:
            x,y = y,x
        while x%y!=0:
            tmp = x
            x = y 
            y = tmp%y 
        return y 
    
    t0 = time.time()
    run() 
    t1 = time.time()
    print "running time=",(t1-t0),"s"
    
                
  • 相关阅读:
    硕士时代的数学知识点小节
    电子科技大学 易查分网站 爬虫 批量爬取成绩
    使用SKlearn(Sci-Kit Learn)进行SVR模型学习
    使用经验风险最小化ERM方法来估计模型误差 开坑
    二分图最大匹配模版 m√(n) 复杂度
    支持向量机SVM 初识
    K-means + PCA + T-SNE 实现高维数据的聚类与可视化
    Bin Packing 装箱问题——NPH问题的暴力枚举 状压DP
    CDQ分治_占坑
    Logistic回归 逻辑回归 练习——以2018建模校赛为数据源
  • 原文地址:https://www.cnblogs.com/bbbblog/p/5008169.html
Copyright © 2020-2023  润新知