zoukankan      html  css  js  c++  java
  • Day7 T1 直角三角形

    题目

    二维平面坐标系中有N个点。从N个点选择3个点,问有多少选法使得这3个点形成直角三角形。

    输入

    第一行包含一个整数N(3 (leqslant) N (leqslant) 1500),表示点数。
    接下来N行,每行包含两个用空格隔开的整数表示每个点的坐标,坐标值在(-10^9)(10^9)之间。每个点位置互不相同。

    输出

    输出直角三角形的数量。

    样例

    输入 输出
    3
    4 2
    2 1
    1 3
    1
    4
    5 0
    2 6
    8 6
    5 7
    0
    5
    -1 1
    -1 0
    0 0
    1 0
    1 1
    7

    题解

      固定一个点P,平移整个坐标系,使得P为原点。现在,对于每个点,首先确定其所在的象限,然后将其旋转k•90°(k∈Z),使其落在第一象限中。之后,按照过点的正比例函数的斜率k(纵坐标除以横坐标)对所有点进行排序。如果两个点斜率相同并且旋转之前在相邻的象限中,它们就能形成以P为直角顶点的直角三角形。排序后,对于每一组斜率相同的点,统计它们原来在每个象限的点的个数,并将相邻象限的点的数量相乘。时间复杂度为(O(N^2logN))。(这就是为什么(O(N^3))的暴力枚举在加一堆玄学优化后也能卡过:因为正解的时间复杂度也不低)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n;
    int x[1510],y[1510];
    ll ans=0;
    
    struct node{
        ll x,y;
        int qua;
    };
    node cpy[1510];
    
    bool cmp(node a,node b){
        return a.y*b.x<a.x*b.y;
        //将不等式变形成两边都是乘法运算,避免除法运算带来的精度损失
    }
    
    void rotate(int m){
        if(cpy[m].x==0 && cpy[m].y==0) return;//如果是原点,无需旋转
        cpy[m].qua=1;
        while(cpy[m].x<=0 || cpy[m].y<0){
            swap(cpy[m].x,cpy[m].y);
            cpy[m].y=-cpy[m].y;
            cpy[m].qua++;//如果一个点需要顺时针旋转n次才落在第一象限,那么其原象限为n+1 
            //最多旋转3次(原来在第四象限),所以这里无需像隔壁熊泽恩同学写的那样取模 
        }
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d %d",&x[i],&y[i]);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                cpy[j].x=x[j]-x[i];
                cpy[j].y=y[j]-y[i];
                rotate(j);
            }
            swap(cpy[1],cpy[i]);//不要把原点给算进去了
            sort(cpy+2,cpy+n+1,cmp);
            int j=2;
            while(j<=n){
                int cnt[5]={0};
                int k=j;
                while(k<=n && cpy[j].y*cpy[k].x==cpy[j].x*cpy[k].y){
                    cnt[cpy[k].qua]++;
                    k++;
                }
                for(int t=1;t<4;t++) ans+=cnt[t]*cnt[t+1];
                ans+=cnt[1]*cnt[4];
                j=k;
            }
        }
        printf("%lld",ans);
        return 0;
    }
    
  • 相关阅读:
    JavaScript设计模式与开发实践
    ECMAScript 6入门
    时间管理微课程:值得永久收藏的25条时间管理技巧
    day14.生成器迭代器作业
    windows下创建MySQL定时备份与删除脚本
    day14.生成器进阶,推导式
    day13.装饰器进阶,迭代器
    day12.生成器;wraps初识
    day11.装饰器初识
    day10.函数升级
  • 原文地址:https://www.cnblogs.com/znk161223/p/11516691.html
Copyright © 2011-2022 走看看