【问题标题】:Efficient way to Find if points form a Square. Calculation C++查找点是否形成正方形的有效方法。计算 C++
【发布时间】:2015-01-06 10:35:21
【问题描述】:

我是新来的。我正在解决一个问题来检查 N 点 (x,y) 是否形成一个正方形。最终输出是点可以形成的正方形数量+最大面积(正方形之一)。 像这样输入:

6
1 1
1 2
1 3
2 3
2 2
2 1

输出:

2 -> (2 Squares were formed)
1 -> (1 was the biggest area)

所以我像这样读取 x 和 y:

cin >> n;
    for(int i=0;i<n;i++)
    {cin >> coordenadas[i].x >> coordenadas[i].y;concat[i]=coordenadas[i].y * 100000 + coordenadas[i].x;}
    sort (concat, concat+n);
    for(int i=0;i<n;i++)
    {
        A.x=coordenadas[i].x;A.y=coordenadas[i].y;
        for(int ii=M;ii<n;ii++)
        {
            B.x=coordenadas[ii].x;
            B.y=coordenadas[ii].y;
            ...
            calculo();
            if(mArea<area)
            mArea=area;
        }
        M+=1;
    }

在下一个函数中,我正在尝试计算 x 和 y var 以获得这样的值 -> http://i.stack.imgur.com/Uqtau.png

但我不确定我的计算。

还有我的演算函数:

void calculo()
{
    int x=0,y=0;
    if(A.x==B.x)
    {
        x=abs(B.y-A.y);
        area=x*x;
        R1.c1=(B.y) * 100000 + (A.x + x);
        R1.c2=(B.y) * 100000 + (A.x - x);
        if (binary_search (concat, concat+n, R1.c1))
        if (binary_search (concat, concat+n, R1.c2))
        quadrados+=1;
        else
        area=0;
    }
    else
    {
        x=abs(B.y-A.y);
        y=abs(B.x-A.x);
        area=sqrt(x*x+y*y)*sqrt(x*x+y*y);
        R1.c1=(B.y + y) * 100000 + (B.x - x);
        R1.c2=(A.y + y) * 100000 + (A.x - x);
        if (binary_search (concat, concat+n, R1.c1))
        if (binary_search (concat, concat+n, R1.c2))
        quadrados+=1;
        else
        area=0;
    }
}

我正在做的是,选择 2 个独特的点并计算可能形成正方形的其他两个点。然后我将它们“连接”成一个唯一的整数(例如(B.y + y)* 100000 +(B.x - x),这意味着 -> y * 100000 +x)然后我用二进制搜索查找它们,如果它们被发现我增加了 n_square 变量。

问题是,我不确定计算是否正常,我需要帮忙。我知道有一种方法可以使用 bitset 进行计算,但我不是专家,所以我不能使用 bitset。我正在尝试获得 O(N^2 * log(V)) 解决方案。给我一些建议

################### 一些评论后的新编辑 -> ############### ####

新输入(评论)

9
5 3
1 4
1 3
1 2
2 1
2 3
3 4
3 2
4 2

输出:

6 (Number of Squares)
0 (Its Area-> I'm not calculating yet)

预期输出

3
5 (Area)

新代码:

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

struct c{

    int x,y;

}A,B,C,D,coordenadas[3001];

int quadrados=0,n=0;
long int area;
long int concat[3001];

int dist2 (c A,c B) {
  int x = A.x - B.x;
  int y = A.y - B.y;
  return x*x + y*y;
}



void calculo()
{
    int d = dist2(A, B);
    const int x = B.x - A.x;
    const int y = B.y - A.y;
    C.x = A.x - y;
    C.y = A.y + x;
    D.x = B.x - y;
    D.y = B.y + x;
    d = dist2(A, B);
    if (dist2(A, C) == d && 2*d == dist2(B, C))
    if (binary_search (concat, concat+n, C.y * 100000 + C.x))
    if (dist2(B, D) == d && dist2(C, D) == d)
    if (binary_search (concat, concat+n, D.y * 100000 + D.x))
    {
        quadrados+=1;
    }

}

int main() {

    int M=1,mArea=0;
    cin >> n;
    for(int i=0;i<n;i++)
    {cin >> coordenadas[i].x >> coordenadas[i].y;concat[i]=coordenadas[i].y * 100000 + coordenadas[i].x;}
    sort (concat, concat+n);
    for(int i=0;i<n;i++)
    {
        A.x=coordenadas[i].x;
        A.y=coordenadas[i].y;
        for(int ii=M;ii<n;ii++)
        {
            B.x=coordenadas[ii].x;
            B.y=coordenadas[ii].y;
            calculo();
            if(mArea<area)
            mArea=area;
        }
        M+=1;
    }

    if(quadrados==0)
    cout << quadrados << endl;
    else
    cout << quadrados << endl << mArea << endl;
    return 0;
}

【问题讨论】:

  • 网格的最大尺寸是多少(如果有),还是像您的示例中那样总是 4x4?
  • 就是一个例子。 N
  • 如果您声明所有点都在网格上会很有帮助。
  • 旋转的正方形呢?他们算吗?
  • 所有这些都算。此外,只允许正坐标

标签: c++ math shape coordinate-systems


【解决方案1】:

从你的照片:

const int x = B.x - A.x;
const int y = B.y - A.y;
C.x = A.x - y;
C.y = A.y + x;
D.x = B.x - y;
D.y = B.y + x;

然后

area = x * x + y * y;

【讨论】:

  • 它适用于所有点还是仅当 A 和 B 位于图像的位置时?
  • 对于AB 之间的所有相对位置(计划中)。
  • 我们有BD = z ^ AB^ 是叉积,z 是与平面正交的单位向量)。
  • 是的,只需测试一下:A.x == B.x,你得到了x == 0C.y = A.yD.y = B.yC.x == D.x == A.x - y == B.x - y
  • 第二个可能的正方形使用 A 和 B,通过用 +y-x 而不是 -y+x 形成 C 和 D。它是您定义的正方形的线 (AB) 的对称正方形。
【解决方案2】:

我假设所有坐标都是整数,并且您选择的类型可以适合最大坐标平方的两倍(在您的情况下为 8 亿 - 不难)。如果需要,可以省略后一个假设,但前者并不那么容易,因为否则您必须决定如何处理舍入。

基本思想是遍历每个点 A 和每个点 B 在列表中出现的时间比 A 晚。计算

int dist2 (A, B) {
  int x = A.x - B.x;
  int y = A.y - B.y;
  return x*x + y*y;
}

int d = dist2(A, B);

所以d 是 A 和 B 之间的平方距离。现在定义

c C1, C2, D;
C1.x = 2*A.x - B.y;
C1.y = B.x;
C2.x = B.y;
C2.y = 2*A.y - B.x;

并检查 C1 (resp., C2) 是否在 B 之后的列表中。如果是,则将其称为 C 并检查是否

dist2(B, D) == d && dist2(C, D) == d

如果是这样,ABCD 是一个正方形。如果您总共有 n 个元素,则前两个循环发生 n(n-1)/2 次,每对导致 2 或 3 次查找,表明算法运行时间为 O(n^2 log n)。

编辑:早期版本还提供了一种更简单的算法,可以在 O(n^3) 时间内运行。它的存在引起了混乱,所以我删除了它并使其他算法更加明确。

【讨论】:

  • 我必须考虑到 C 和 D 就像最后一个答案? ## const int x = B.x - A.x; ## const int y = B.y - A.y; C.x = A.x - y; ## C.y = A.y + x; ## D.x = B.x - y; ## D.y = B.y + x; ## 如何计算 C 和 D 以便稍后检查是否为正方形? (使用你的功能)
  • 在第一种方法中,您只有四个嵌套循环,分别为您提供 A、B、C 和 D。在第二种方法中,您计算​​ C 的两种不同可能性并尝试每一种(然后计算 D ,如果 C 存在于您的列表中)。
  • i.imgur.com/2ztg28Z.png -> 我正在这样做。问题是它计数到很多平方。如果我在我的主题中使用最后一个输入(我编辑过),它应该只有 3 个方块,因为:i.imgur.com/Xiq87DQ.png 而不是 6(它算 6)
  • @NewYear:好吧,你没有使用我给出的方法,所以我只能建议一个一般性的提示:当你认为你已经找到时,打印点 A、B、C 和 D一场比赛。要么你会看到它在重复计算某个正方形,或者它包含了一些不形成正方形的点。
  • OP 的解决方案是(巧妙地)O(N**2 ln N),所以这并没有真正实现。
猜你喜欢
  • 2015-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多