题目链接:http://codeforces.com/contest/1163/problem/C2
题意:现在有
n
n
n个点,每两个点可以形成一条直线,问有多少对直线相交。
解题心得:
n
n
n条个点最多可以形成
n
∗
(
n
−
1
)
n*(n-1)
n∗(n−1)条直线(三点同线算形成一条直线),
n
n
n的范围是
1000
1000
1000,
1
,
000
,
000
1,000,000
1,000,000条直线是可以接受的。两条直线不平行必然相交,假设所有直线两两相交,这样直线对数量为
1
0
12
10^{12}
1012,也是可以接受的。这个题最难的就是处理三(多)点同线的问题,遍历每一个点与其他点形成的直线,如果当前点分别与其他两个点形成的直线斜率相同那么其他两个点形成的直线就会被覆盖掉,这样可以直接二分查找当前点与其他点形成的斜率,如果有相同该覆盖的覆盖就行了。复杂度是
n
∗
n
∗
l
o
g
n
n*n*logn
n∗n∗logn。最后将所有的直线按照斜率排序,斜率相同的必然就是平行且不重合的直线。然后用
n
∗
(
n
−
1
)
n*(n-1)
n∗(n−1)减去相关的平行直线多算出的答案就行了。
#include <bits/stdc++.h>
using namespace std
;
const int maxn
= 1050;
const double esp
= 1e-9;
int n
;
struct Node
{
double x
, y
;
}node
[maxn
];
struct Line
{
int a
, b
;
double k
;
bool flag
;
bool operator
< (const Line
& x
) const {
if(this
->k
!= x
.k
) {
return this
->k
< x
.k
;
} else if(this
->a
!= x
.a
) {
return this
->a
< x
.a
;
} else if(this
->b
!= x
.b
) {
return this
->b
< x
.b
;
} else if(this
->flag
!= x
.flag
) {
return this
->flag
< x
.flag
;
}
}
};
vector
<double> ve
;
set
<Line
> temp
;
set
<Line
> ::iterator iter
;
map
<pair
<int,int>, int> maps
;
void init() {
scanf("%d", &n
);
for(int i
=1;i
<=n
;i
++) {
scanf("%lf%lf", &node
[i
].x
, &node
[i
].y
);
}
for(int i
=1;i
<=n
;i
++) {
for(int j
=i
+1;j
<=n
;j
++) {
double k
;
if(fabs(node
[j
].x
- node
[i
].x
) < esp
) {
k
= 1e9+233;
} else {
k
= (node
[j
].y
- node
[i
].y
) / (node
[j
].x
- node
[i
].x
);
}
bool flag
= false
;
iter
= temp
.lower_bound({0, 0, k
, false
});
if(iter
!=temp
.end() && fabs(iter
->k
- k
) < esp
) {
maps
[make_pair(iter
->b
, j
)] = 1;
flag
= true
;
}
iter
= temp
.lower_bound({0, 0, k
, true
});
if(iter
!=temp
.end() && fabs(iter
->k
- k
) < esp
) {
maps
[make_pair(iter
->b
, j
)] = 1;
flag
= true
;
}
if(!flag
) {
if(maps
[make_pair(i
, j
)]) {
temp
.insert({i
, j
, k
, false
});
} else {
temp
.insert({i
, j
, k
, true
});
}
} else {
temp
.insert({i
, j
, k
, false
});
}
}
for(iter
=temp
.begin();iter
!=temp
.end();iter
++) {
if(!(iter
->flag
)) continue;
ve
.push_back(iter
->k
);
}
temp
.clear();
}
}
int main() {
init();
long long ans
= 1ll * (ve
.size()-1+1)*(ve
.size()-1)/2;
sort(ve
.begin(), ve
.end());
long long now
= 1;
for(int i
=0;i
<ve
.size()-1;i
++) {
if(ve
[i
] == ve
[i
+1]) {
now
++;
} else {
ans
-= 1ll * (now
- 1 + 1) * (now
- 1) / 2;
now
= 1;
}
}
ans
-= 1ll * (now
- 1 + 1) * (now
- 1) / 2;
printf("%lld", ans
);
return 0;
}