问题描述:
给定2维平面上n个整点的坐标,一条直线最多能过几个点?
输入格式:
第一行一个整数n表示点的个数
以下n行,每行2个整数分别表示每个点的x,y坐标。
输出格式:
输出一个整数表示答案。
样例输入:
5
0 0
1 1
2 2
0 3
2 3
样例输出:
3
思路:
在初中的数学中,我们都知道两点可以确定一条直线,而怎么判断另外一个点是否在直线上呢,其实我们可以通过已知直线的一点和另外一个点通过点斜式的方式 :
( y1 - y0) / ( x1 - x0) = ( y1 - y 3) / ( x1 - x3)
其中红色和绿色是代表原先构成直线的两个点,而黑色的则是代码第3个点,我们通过判断第三点和构成直线的其中一点的斜率是否相同,这里可能有小伙伴就会问了,如果那两条直线的斜率相等,但是是平行不相交的关系怎么办呢?其实不用担心,因为第三个点和直线的其中一点新构成的直线必定是会与本来的那条是重合的关系的,这时如果斜率不相同,那么两根线的必定不会重合,也就是那根线就不会在原来的直线上。
继续观察,我们就拿题目中的例子来看,5个x,y的坐标点,我们需要两两组合依次成为新的直线。
static boolean vit[];
for (int i = 0; i < N; i++){
if (!vit[i]){
vit[i] = true;
}
for (int k = i + 1; k < N; k++){
vit[k] = true;
}
temp = Math.max(temp,count);
count = 0;
vit[k] = false;
System.out.println(temp + 2);
}
因此我使用了布尔类型的一维数组,把遍历的点都标记为true,然后内嵌套一层循环把这个点以下的点都遍历一次。遍历完成后把内层循环的点的布尔值重新设置为false,方便外层遍历的时候使用。最后我把每次的情况都与上一次进行比较,把大的留下,因为我在计算遍历的时候是除去了原来的构成直线的两点,因此在输出的时候还需要加上2。
但是我按照上面的思路发现写的时候,发现运算超时了!!!
上源码:
double a = (arr[k][1] - arr[i][1]) / (arr[k][0] - arr[i][0]);
for (int j = 0; j < N; j++){
if (!vit[j]){
if ( (arr[j][1] - arr[i][1]) / (arr[j][0] - arr[i][0]) == a ){
count++;
}
}
}
而我觉得很大问题就出现在这个,程序运算进行除法时,哪怕你声明成为double类型,先比较与int类型而言,运算更快,但是如果是还是这样进行运算的话,会出现精度的损失!!!因为int会直接取消小数点后面的数值 这时1.5也等于1.4了。
因此我在上面的那条等式中改变了思路;
(y1 - y0) / (x1 - x0) = (y1 - y 3) / (x1 - x3) 等价于 (y1 - y0) * (x1 - x3) = (y1 - y 3) * (x1 - x0)
这样换成乘法问题就得到了解决啦。
完整代码:
import java.util.Scanner;
public class Main {
static int N;
static boolean vit[];
static int arr[][];
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
N = scan.nextInt();
arr = new int[N+1][2];
vit = new boolean[N];
for (int i = 0 ; i < N; i++){
for (int j = 0; j < arr[i].length; j++){
arr[i][j] = scan.nextInt();
}
}
dfs();
}
public static void dfs(){
int count = 0;
int temp = 0;
for (int i = 0; i < N; i++){
if (!vit[i]){
vit[i] = true;
for (int k = i + 1; k < N; k++){
vit[k] = true;
int dy = arr[k][1] - arr[i][1];
int dx = arr[k][0] - arr[i][0];
for (int j = 0; j < N; j++){
if (!vit[j]){
if ( (arr[j][1] - arr[i][1]) * dx == (arr[j][0] - arr[i][0]) * dy ){
count++;
}
}
}
temp = Math.max(temp,count);
count = 0;
vit[k] = false;
}
}
}
System.out.println(temp + 2);
}
}