问题是,通过给出x0,y0,x1,y1给n行。获取集合点数。三点或更多线不相交。行通过(x0,y0),(x1,y1)。不会有同一行。 我有一个想法是先声明一个HashMap,当有新行出现时,得到它的斜坡。如果slop值不在HashMap中,则结果=结果+我们现在有多少行。如果该坡度位于HashMap中,则结果= result +(我们现在有多少行-此坡度有多少行)。 这是我的主要代码部分。
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int[][] lines = new int[in.nextInt()][4];
Map<Double, Integer> map = new HashMap<>();
int cross = 0;
for(int i = 0; i< lines.length; i++){
for(int j = 0; j< 4; j++)
lines[i][j] = in.nextInt();
double slop;
if(lines[i][2] - lines[i][0] == 0)
slop = Double.POSITIVE_INFINITY;
else
slop = (double)(lines[i][3] - lines[i][1]) / (lines[i][2] - lines[i][0]);
if(!map.containsKey(slop)) {
cross = cross + i;
map.put(slop, 1);
}else{
cross = cross + (i - map.get(slop));
map.put(slop, map.get(slop) + 1);
}
}
System.out.print(cross + "\n");
}
但是测试结果表明这是错误的。有人可以帮助我解决我没有注意到的情况,或者我的代码有什么问题吗。
答案 0 :(得分:0)
任何一对不平行的线都将相交。
因此,交点数是唯一斜率数的多项式函数。
将直线的斜率指定为Rise/Run
,但是直接使用该除法是危险的,因为在浮点数学中4.2/2.2
和8.4/4.4
可能不会得出相同的结果。同样,减去x0-x1
可能会导致浮点怪异。
由于看起来好像您是以整数形式读取坐标,因此请考虑将斜率存储为(Rise,Run)
对。但是请注意-Rise/Run
和Rise/-Run
看起来有所不同;因此,请约定,如果斜率为负,则该符号应存储在Rise
中。现在,也许可以使用GCD algorithm简化分数。
现在,您的坡度有了独特而精确的形式(比以前更好了)。
现在,请像以前一样进行操作:如果斜率是唯一的,则斜率的数量会增加哈希集中已有条目的数量。
答案 1 :(得分:0)
这是一个很好的小问题。由于我们正在处理线,而且我们知道同一条线不会出现两次,并且我们知道同一条交点不会出现两次,因此解决方案几乎就像计数一个一样简单每对线的交点,即n * (n-1) / 2
。但是,这假设每对线都有一个交点,如果有任何线是平行的,那是不正确的。因此我们需要计算每个斜率有多少条线共享同一斜率。看来您已经知道了。
但是,从代码中尚不清楚您是否正确使用了这些斜率计数来计算交点数。循环中存在一些加法和减法,这很难推理。如果在两个单独的阶段中执行该算法,则该算法将更加简洁。
如果有r
条线具有相同的斜率,则n * (n-1) / 2
公式假定它们将形成r * (r-1) / 2
个交点,但是由于这些线是平行的,因此它们实际上在0个交点处他们。因此,我们需要减去r * (r-1) / 2
来纠正计数。我们需要针对每个坡度独立进行此操作。
因此该算法可以按以下方式工作:
total
初始化为n * (n-1) / 2
,其中n
是行数。r
,从总数中减去r * (r-1) / 2
。这是一个实现:
import java.util.Map;
import java.util.HashMap;
import java.util.Scanner;
public class CountIntersections {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
long n = in.nextInt();
Map<Double, Integer> slopeCounts = new HashMap<>();
for(int i = 0; i < n; i++) {
int x0 = in.nextInt(), y0 = in.nextInt(),
x1 = in.nextInt(), y1 = in.nextInt();
double slope;
if(x0 == x1) {
slope = Double.POSITIVE_INFINITY;
} else {
slope = (double) (y1 - y0) / (x1 - x0);
}
slopeCounts.put(slope, slopeCounts.getOrDefault(slope, 0) + 1);
}
long total = n * (n-1) / 2;
for(long r : slopeCounts.values()) {
total -= r * (r-1) / 2;
}
System.out.println(total);
}
}
将变量n
,total
和r
声明为类型long
而不是int
,这样乘法n * (n-1)
就不会overflow。对于n
和/或r
的值大于约46,000的问题。
请注意,此处将斜率计算为double
没有问题。从扫描仪读取的数字是int
,所有数字都可以精确地表示为double
。相减将是精确的,the IEEE 754 specification guarantees that division of floating point numbers will be correctly rounded。因此,由于浮点运算的原因,数值不精确度不会导致两个等斜率的计算略有不同。