【问题描述】
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。
给定平面上 2 × 3 2 × 32×3 个整点 ( x , y ) ∣ 0 ≤ x < 2 , 0 ≤ y < 3 , x ∈ Z , y ∈ Z {(x,y)|0 ≤ x < 2,0 ≤ y < 3, x ∈ Z,y ∈ Z}(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z,即横坐标是 0 00 到 1 11 (包含 0 00 和 1 11) 之间的整数、纵坐标是 0 00 到 2 22 (包含 0 00 和 2 22) 之间的整数的点。这些点一共确定了 11 1111 条不同的直线。
给定平面上 20 × 21 20 × 2120×21 个整点 ( x , y ) ∣ 0 ≤ x < 20 , 0 ≤ y < 21 , x ∈ Z , y ∈ Z {(x,y)|0 ≤ x < 20,0 ≤ y < 21, x ∈ Z,y ∈ Z}(x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z,即横坐标是 0 00 到 19 1919 (包含 0 00 和 19 1919) 之间的整数、纵坐标是 0 00 到 20 2020 (包含 0 00 和 20 2020) 之间的整数的点。请问这些点一共确定了多少条不同的直线。
【答案】
40257
基本思路:
通过点斜式y=kx+b确定每条直线唯一的k和b。
其中:
k=(y2-y1)/(x2-x1) (这里并没有用double进行存储,将分母分子通分后,再存入string类型,下同)
b=(x1y2-x2y1)/(x1-x2)
代码
import java.util.*;
public class Main {
public static void main(String[] args) {
Set<String> set=new HashSet<String>();
//四个for循环为两两确定一个坐标
for (int x1 = 0; x1 < 20; x1++) {
for (int y1 = 0; y1 < 21; y1++) {
for (int x2 = 0; x2 < 20; x2++) {
for (int y2 = 0; y2 < 21; y2++) {
//如果两点相同则跳过
if (x1==x2 && y1==y2) {
continue;
}
int up =x2-x1;
int down =y2-y1;
if (x1==x2) {
set.add("x="+x1);
continue;
}
int tmp=gcd(up,down);
String k=down/tmp+"/"+up/tmp;
up=x1*y2-x2*y1;
down=x1-x2;
tmp=gcd(up,down);
String b=up/tmp+"/"+down/tmp;
String key=k+" "+b;
set.add(key);
}
}
}
}
System.out.println(set.size());
}
public static int gcd(int x ,int y) {
return y==0 ? x : gcd(y,x%y);
}
}