题目描述:
在平面直角坐标系中,两点可以确定一条直线。
如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。
给定平面上2 × 3 个整点{(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z},
即横坐标是0 到1 (包含0 和1) 之间的整数、纵坐标是0 到2 (包含0 和2) 之间的整数的点。
这些点一共确定了11 条不同的直线。
给定平面上20 × 21 个整点{(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},
即横坐标是0 到19 (包含0 和19) 之间的整数、纵坐标是0 到20 (包含0 和20) 之间的整数的点。
请问这些点一共确定了多少条不同的直线。
思路:
直接先获取每个点,然后再通过y=kx+b来确定两点之间的直线。
若是用double类型来处理斜率k,会有误差,因此直接用String的形式来表示直线,斜率直接表示为(y2-y1)/(x1-x2)的形式,但分子分母要同时除以最大公因数,来排除重复的情况。b也通过同样的方法来表示。
由于本题的点都不超过两位数,因此采用整形的x*100+y表示一个点。获取点的时候再/100或者%100来获取x和y。
获取每个点:
List<Integer> list = new ArrayList<>(); // 存放每个点的List集合
Set<String> res = new HashSet<>(); // 存放直线的集合,HashSet不能重复
for (int i=0;i<20;i++) {
for (int j = 0; j < 21; j++) { // 每个点以i*100+j的形式存放
list.add(i * 100 + j);
}
}
斜率k和b的处理:
对b的处理时,如下:
int len = list.size(); // 点的数量
for (int i=0;i<len;i++){
int dot1 = list.get(i); // 获取当前点
int x1 = dot1/100, y1 = dot1%100; // 当前点的x和y值
for (int j=i+1;j<len;j++){
int dot2 = list.get(j); // 获取下一个点
int x2 = dot2/100, y2 = dot2%100; // 下一个点的x和y值
int ky = y2-y1, kx = x2-x1; // y和x之差的比值就是斜率
if (kx==0){
res.add("x="+x1); // 当斜率不存在时的处理
continue;
}
int gcd1 = gcd(ky,kx); // 获取y的差和x的差的最大公因数,以便排除同一条直线
String K = ky/gcd1+"/"+kx/gcd1; // K就是斜率的表示情况
int temp = y1*kx - x1*ky; // 用来计算切点B
int gcd2 = gcd(temp,kx);
String B = temp/gcd2+"/"+kx/gcd2;
res.add(K+" "+B); // 用K和B表示直线
}
}
完整代码:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class 直线2021 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(); // 存放每个点的List集合
Set<String> res = new HashSet<>(); // 存放直线的集合,HashSet不能重复
for (int i=0;i<20;i++) {
for (int j = 0; j < 21; j++) { // 每个点以i*100+j的形式存放
list.add(i * 100 + j);
}
}
int len = list.size(); // 点的数量
for (int i=0;i<len;i++){
int dot1 = list.get(i); // 获取当前点
int x1 = dot1/100, y1 = dot1%100; // 当前点的x和y值
for (int j=i+1;j<len;j++){
int dot2 = list.get(j); // 获取下一个点
int x2 = dot2/100, y2 = dot2%100; // 下一个点的x和y值
int ky = y2-y1, kx = x2-x1; // y和x之差的比值就是斜率
if (kx==0){
res.add("x="+x1); // 当斜率不存在时的处理
continue;
}
int gcd1 = gcd(ky,kx); // 获取y的差和x的差的最大公因数,以便排除同一条直线
String K = ky/gcd1+"/"+kx/gcd1; // K就是斜率的表示情况
int temp = y1*kx - x1*ky; // 用来计算切点B
int gcd2 = gcd(temp,kx);
String B = temp/gcd2+"/"+kx/gcd2;
res.add(K+" "+B); // 用K和B表示直线
}
}
System.out.println(res.size());
}
private static int gcd(int a, int b){ // 获取最大公约数的函数
return b==0?a:gcd(b,a%b);
}
}