題名
ポータル。
平面上のいくつかの点を指定して、それらから6つの点を選択して2つの三角形を形成し、選択した点があれば、2つの三角形をばらばらにする(つまり、同時に2つの三角形に属する平面上の点がない)解の数を見つけます。同じであるが異なる三角形は、異なるソリューションと見なされます。
分析
まず、結論があります。2つの三角形が交差しない場合、2つの内部共通接線が存在する必要があります。以下に示すように(知覚的に理解する):
次に、内側の共通接線を列挙できます。
入力の各ポイントについて、それと他のn − 1 n-1n−1点が直線を形成し、極角をソートし、直線の右側の点数を維持しながら反時計回りにこれらの直線を列挙します。各直線について、乗算原理を使用してスキームを計算します。
いくつかの小さな詳細があります。各直線は実際には2つの三角形を形成できます。上図に示すように、直線CE CEC Eが形成することができる△ABC \三角形ABCを△ A B Cと△DEF \三角形DEF△ D E F、も形成することができる△ABE \三角形ABEを△ A B Eと△CDF \三角形CDF△ C D F.。あなたが計算するたびだから、あなたは乗算を持っている2 22。ただし、各三角形は2つの直線で同時に計算されるため、最終的な答えを再度半分にする必要があります。これは実際には完全に相殺されます。
同時に、00未満の極角のみを列挙します。0の直線は、大きな共線性を防ぎます。
コード
#include <bits/stdc++.h>
#define ll long long
#define MAX 2005
using namespace std;
const double PI = acos(-1.0);
struct vec{
double x, y;
}a[MAX];
int n;
double b[MAX];
ll ans;
ll C2(ll x){
return (x-1)*x/2;
}
int main()
{
cin >> n;
for (int i = 1; i <= n; ++i) {
scanf("%lf%lf", &a[i].x, &a[i].y);
}
for (int i = 1; i <= n; ++i) {
int cnt = 0;
for (int j = 1; j <= n; ++j) {
if(i != j){
b[++cnt] = atan2(a[j].y-a[i].y, a[j].x-a[i].x);
}
}
sort(b+1, b+cnt+1);
for (int j = 1, k = 1; j <= cnt && b[j] <= 0; ++j) {
while(k <= cnt && b[k]-b[j] < PI){
//在直线右侧。
k++;
}
ll l = k-j-1, r = cnt-l-1; //注意一下点的个数细节:当前点和当前k不能算
ans += C2(l)*C2(r); //乘法原理
}
}
cout << ans << endl;
return 0;
}