计算直角三角形

时间:2017-12-28 13:13:31

标签: c++ algorithm

如果给你一组点,你需要找到可以用这些点制作的直角三角形的数量(两边平行于x和y轴),这将是一种有效的方法。做到了吗?

我想出了一些代码,用来检查每个给定点是否有一条线(除了我摆脱的一些个别点)

这是我的代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin>>n;
    vector<int> storex[100010];
    vector<int> storey[100010];
    vector< pair< int,int > > singlepoints;
    vector<int> canstorex;
    int pointsx[100010];
    int pointsy[100010];
    vector<int> canstorey;
    for(int i=0;i<n;i++){
        int x,y;
        cin>>x>>y;
        storex[x].push_back(y);
        storey[y].push_back(x);
    }
    for(int i=0;i<100010;i++){
        if(storex[i].size()>1){
            /*if(storex[i].size() == 1){
                singlepoints.push_back(make_pair(i,storex[i][0]));
            }*/   
            canstorex.push_back(i);
            pointsx[i] = storex[i].size();
        }
        if(storey[i].size()>1){
            /*if(storey[i].size() == 1){
                singlepoints.push_back(make_pair(storex[i][0],i));
            }*/
            canstorey.push_back(i);
            pointsy[i] = storey[i].size();
        }
    }
    int count = 0;
    for(int i =0;i<canstorex.size();i++){
        int temp = canstorex[i];
        //std::cout<<storex[temp].size()<<endl;
        for(int j =0;j<storex[temp].size();j++){
            int tempcount = 0;
            if(storey[storex[temp][j]].size()>1){
                //std::cout<<pointsx[temp]<<endl;
                tempcount+=(storey[storex[temp][j]].size()-1);

                if(pointsx[temp]>2){

                    tempcount*= (pointsx[temp]-1);

                }
                if(pointsy[storex[temp][j]]>2){

                    tempcount*= (pointsy[storex[temp][j]]-1);

                }
            }
            count +=tempcount;


        }
    }
    std::cout<<count;
    /*for(int i =0;i<canstorey.size();i++){

    }*/
}

1 个答案:

答案 0 :(得分:0)

假设你的点是整数,你只想要一边与x轴平行的三角形,另一边与y轴平行,第三边连接两边不是两边交点,那么我将在容器中的x上的数据和在另一个容器中的y上的数据进行排序。

对于第一个容器,我也会在x中匹配y个点。比较函子看起来像:

class CompareXY
{
    bool operator()(const &Point lhs, const &Point rhs) const
    {
        return lhx.x != rhs.x ? lhs.x < rhs.x : lhs.y < rhs.y;
    }
};

对于第二个容器,您将反转比较(class CompareYX)。

然后你会遍历x。对于每个x至少有一个具有相同x的另一个点(你应该计算它们 - 见下文),我会计算具有相同y(但是不同的x)的点的数量。

您可以使用std::equal_range查找给定y的范围,然后使用std::count_if计算有效制作直角三角形的点数。

此时,您将上述两个计数步骤中的点数相乘,并将其与累积的三角形数量相加。

您已正确排序数据的事实允许您限制每个x或y的检查次数。

完成后,您可以根据数据进行额外的优化。你可能想要考虑的事情是:

  • 对两个容器的x和y数据进行排序是否有用?
  • 某些std::equal_range可以替换为std::lower_bound吗?
  • 你可以在某些步骤做一些额外的过滤,以消除一些数据或一些检查。
  • 如果您有很多重复点,您可能需要检查它们并将该点的结果乘以相同点数。

您可能尝试的一件事是最初进行更具侵略性的过滤。我不确定它是否会有所帮助。你必须衡量绩效。一个想法是:

  • 您在y上排序并删除任何没有任何匹配y的点(不能是任何直角与轴平行的直角三角形的一部分)。
  • 您复制该数据并对x进行排序,并删除任何没有匹配x的点。

在这种情况下,我可能会先进行组合(y然后x x然后y)排序以避免额外排序。

顺便说一下,根据数据,性能可能会有很大差异。因此,用实际数据衡量性能以查看其效果可能是个好主意。在x或y坐标范围很大(比如说超过几千)时,您将拥有非常少的直角三角形,因此激烈的初始过滤可能有助于更快地减少数据大小,从而提高剩余步骤的性能。另一方面,如果数据在x和y坐标中被压缩,初始过滤将浪费时间,因为无论如何大多数数据都会被保留,因此无论如何都要重新检查。