题目描述
给定一个二维平面上的 n个不重合的点 ,请问存在几个三元组,使得他们两两相连之后,可以构成一个三角形。
输入
第一行一个整数 n,表示点的个数。
接下来 n 行,每行两个整数 ,表示一个平面上的点。
输出
一个整数,表示能构成的三角形个数。
样例输入
4
0 1
1 3
1 1
-1 -1
样例输出
3
代码 :
思路 : Cn3 为所有可能性,再减去共线的三角形数
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
int n;
scanf("%d", &n);
vector<pair<int,int>> a(n);
for(int i = 0 ; i < n; ++ i) {
scanf("%d%d", &a[i].first, &a[i].second);
}
///sort(a.begin(), a.end());
int ans = n * (n - 1) * (n - 2) / 6 ;
for(int i = 0; i < n - 2; ++ i) {
for(int j = i + 1; j < n - 1; ++ j) {
for(int k = j + 1; k < n; ++ k) {
int x1 = a[i].first - a[j].first;
int x2 = a[i].first - a[k].first;
int y1 = a[i].second - a[j].second;
int y2 = a[i].second - a[k].second;
if(x1 * y2 == x2 * y1) -- ans;
}
}
}
printf("%d\n", ans);
return 0;
}
三点共线判断方式 :
(1) 斜率法 :
int x1 = a[i].first - a[j].first;
int x2 = a[i].first - a[k].first;
int y1 = a[i].second - a[j].second;
int y2 = a[i].second - a[k].second;
if(x1 == 0 || x2 == 0) {
if(x1 != x2) continue;
else -- ans;
}
else {
long double t1 = 1.0 * y1 / x1, t2 = 1.0 * y2 / x2;
if(t1 == t2) -- ans;
}
//!!!! 这种方法存在问题, 就是精度不够, 哪怕是long double 也不够
(2) 向量叉乘
向量a = (x1, y1), 向量 b = (x2, y2)
a *(叉乘) b = x1 * y2 - y1 * x2 (矢量,平行于z 轴)
结果为 0 说明 共线
PS :: 三维 a = (x1, y1, z1), b = (x2, y2, z2)
result = (y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2)
int x1 = a[i].first - a[j].first;
int x2 = a[i].first - a[k].first;
int y1 = a[i].second - a[j].second;
int y2 = a[i].second - a[k].second;
if(x1 * y2 == x2 * y1) -- ans;
(3) 面积法
利用行列式 求解
S = 1/2[x1 * (y2-y3) - y1 * (x2-x3) +(x2 * y3 - x3 * y2)]
// 判断三点是否共线的函数,使用面积法
bool isCollinear(int x1, int y1, int x2, int y2, int x3, y3) {
return (x1 * (y2 - y3) - y1 * (x2 - x3) + (x2 * y3 - x3 * y2)) == 0;
}