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"); } }
上面给出来很好的不用暴力的方法
对于直角在原点的情况:
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"