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 #
# 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"