#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
//res是有多少种选法
int n,res;
//存当前坐标的点有多少个
map<pair<int,int>,int> geshu;
void solve(){
cin>>n;
//动态数组,每一行又是一个有两个元素的数组,用来存每个点的坐标
vector<array<int,2>> a(n);
for(int i=0;i<n;i++){
cin>>a[i][0]>>a[i][1];
geshu[{a[i][0],a[i][1]}]++;
}
//a[i]是顶点
for(int i=0;i<n;i++){
//存 到当前顶点,距离为d的点的集合,相当于位于同一个圆上
//键是半径,值是相同半径的点的集合
map<int,vector<int>> b;
for(int j=0;j<n;j++){
//d是半径(a[j]点到顶点的距离)
//这里不用开平方,因为开平方会有小数,会有精度的问题,所以不用开方了,反正答案一样
int d=(a[i][0]-a[j][0])*(a[i][0]-a[j][0])+(a[i][1]-a[j][1])*(a[i][1]-a[j][1]);
b[d].push_back(j);
}
//遍历不同的半径(不同的圆)
for(auto t:b){
//map的键用b.first,值用b.second
vector<int> b=t.second;
//相同圆上的点的数量
int cnt=b.size();
//用高中学过的排列组合中的组合数公式,CM2,即从m个里面选2个
res+=cnt*(cnt-1)/2;
//del是三点共线的情况,组不成三角形,要去掉
int del=0;
//遍历此半径上的不同点
for(int j=0;j<cnt;j++){
//顶点的坐标
int x1=a[i][0],y1=a[i][1];
//当前点的坐标
int x2=a[b[j]][0],y2=a[b[j]][1];
//会和当前点和顶点在同一条线上的坐标
int x=2*x1-x2,y=2*y1-y2;
del+=geshu[{x,y}];
}
//因为一个点和另一个点在一条线上,那么这个点和另一个点判断时会各判断共线一次
//会重复,所以得除以二
//去掉共线的情况
res-=del/2;
}
}
cout<<res;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
1. 数三角-枚举-STL
于 2024-05-12 13:36:03 首次发布