格点图的等腰三角形判定--枚举的优化

发布时间 2023-03-28 22:11:41作者: 重生之我是菜鸟


https://ac.nowcoder.com/acm/contest/52441/F

  • 考虑到是格点图,不存在三个点能构成等边三角形,即无需考虑等边三角形的去重。
  • 对于一个等腰三角形,去枚举这个等腰三角形的顶点p,对于这个顶点,再开一个距离的桶cnt,cnt[m]为到这个顶点距离为m的点的个数。再去枚举其他的点q,在枚举过程中的cnt[dij(p,q)]即为对答案的贡献。最后考虑共线的情况,即反方向延长,看延长出的点有没有在输出中出现过即可,记录次数为line,最后的答案要减去line*2,因为会计算两次。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
    int x,y;
}arr[3050];
int vis[4000][4000];
int cnt[3000010];
int dij(int i,int j){
    return (arr[i].x-arr[j].x)*(arr[i].x-arr[j].x)+(arr[i].y-arr[j].y)*(arr[i].y-arr[j].y);
}
int main(){
    cin>>n;
    for(int i = 1;i<=n;i++) {
        cin>>arr[i].x>>arr[i].y;
        vis[arr[i].x+1500][arr[i].y+1500] = 1;
    }
    int ans = 0;
    int line = 0;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=n;j++){
            if(i==j) continue;
            ans += cnt[dij(i,j)];//枚举到当前这个点时,前面到顶点距离为dij(i,j)的点出现的次数
            cnt[dij(i,j)]++;//次数++
            if(vis[arr[i].x-(arr[j].x-arr[i].x)+1500][arr[i].y-(arr[j].y-arr[i].y)+1500])
			//检查共线的情况
			line++;
        }
        for(int j = 1;j<=n;j++){
            if(i==j) continue;
            cnt[dij(i,j)] = 0;
        }
    }
    cout<<(ans-line/2);
}