我有笛卡尔坐标系中各个点的坐标(坐标是整数),我需要计算我可以在它们上构造的等边三角形和等腰三角形的数量.我怎样才能尽可能及时地做到这一点?

我用C写代码,并试图将所有可能的点对之间的距离存储在哈希表中,这样我就不必再计算距离了,但我相信有一个更有效的解决方案.

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TABLE_SIZE 10007 // Prime number for table size

typedef struct {
    int firstPoint[2]; // Coordinates of point 1
    int secondPoint[2]; // Coordinates of point 2
    int distanceSquared; // Distance squared between points
} HashTableEntry;

unsigned int jenkins_hash(const void *key, size_t length) {
    const unsigned char *data = key;
    unsigned int hash = 0;
    size_t i;

    for (i = 0; i < length; ++i) {
        hash += data[i];
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
    hash += (hash << 3);
    hash ^= (hash >> 11);
    hash += (hash << 15);

    return hash;
}

unsigned int hash(int firstPoint[2], int secondPoint[2]) {
    unsigned char key[8];
    memcpy(&key[0], &firstPoint[0], sizeof(int));
    memcpy(&key[4], &secondPoint[0], sizeof(int));
    return jenkins_hash(key, sizeof(key)) % TABLE_SIZE;
}

void insert(HashTableEntry** table, int firstPoint[2], int secondPoint[2], int distanceSquared) {
    unsigned int index = hash(firstPoint, secondPoint);
    while (table[index] != NULL) {
        index = (index + 1) % TABLE_SIZE; // Linear probing
    }
    table[index] = (HashTableEntry*)malloc(sizeof(HashTableEntry));
    if (table[index] == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }
    memcpy(table[index]->firstPoint, firstPoint, sizeof(int) * 2);
    memcpy(table[index]->secondPoint, secondPoint, sizeof(int) * 2);
    table[index]->distanceSquared = distanceSquared;
}

int getDistanceSquared(HashTableEntry** table, int firstPoint[2], int secondPoint[2]) {
    unsigned int index = hash(firstPoint, secondPoint);
    HashTableEntry* entry;
    while ((entry = table[index]) != NULL) {
        if (entry->firstPoint[0] == firstPoint[0] && entry->firstPoint[1] == firstPoint[1] &&
            entry->secondPoint[0] == secondPoint[0] && entry->secondPoint[1] == secondPoint[1]) {
            return entry->distanceSquared; // Distance squared found
        }
        index = (index + 1) % TABLE_SIZE; // Linear probing
    }
    return -1; // Distance squared not found
}

int calculateDistanceSquared(int x1, int y1, int x2, int y2) {
    return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
}

// Function to count the number of isosceles triangles
int countIsoscelesTriangles(int N, int points[][2], HashTableEntry** table) {
    int count = 0;
    for (int i = 0; i < N - 1; ++i) {
        for (int j = i + 1; j < N; ++j) {
            int distSquared_ij = getDistanceSquared(table, points[i], points[j]);
            for (int k = j + 1; k < N; ++k) {
                int distSquared_ik = getDistanceSquared(table, points[i], points[k]);
                int distSquared_jk = getDistanceSquared(table, points[j], points[k]);
                if (distSquared_ij == distSquared_ik || distSquared_ij == distSquared_jk || distSquared_ik == distSquared_jk) {
                    count++;
                }
            }
        }
    }
    return count;
}

// Function to count the number of equilateral triangles
int countEquilateralTriangles(int N, int points[][2], HashTableEntry** table) {
    int count = 0;
    for (int i = 0; i < N - 1; ++i) {
        for (int j = i + 1; j < N; ++j) {
            int distSquared_ij = getDistanceSquared(table, points[i], points[j]);
            for (int k = j + 1; k < N; ++k) {
                int distSquared_ik = getDistanceSquared(table, points[i], points[k]);
                int distSquared_jk = getDistanceSquared(table, points[j], points[k]);
                if (distSquared_ij == distSquared_ik && distSquared_ij == distSquared_jk) {
                    count++;
                }
            }
        }
    }
    return count;
}

void destroyHashTable(HashTableEntry** table) {
    for (int i = 0; i < TABLE_SIZE; ++i) {
        free(table[i]);
    }
    free(table);
}

int main() {
    int N, T;
    char buffer[256];

    fgets(buffer, sizeof(buffer), stdin);
    sscanf(buffer, "%d %d", &N, &T);

    int (*points)[2] = malloc(N * sizeof(*points));
    if (points == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < N; ++i) {
        fgets(buffer, sizeof(buffer), stdin);
        sscanf(buffer, "%d %d", &points[i][0], &points[i][1]);
    }

    HashTableEntry** table = calloc(TABLE_SIZE, sizeof(HashTableEntry*));
    if (table == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < N - 1; ++i) {
        for (int j = i + 1; j < N; ++j) {
            int distanceSquared = calculateDistanceSquared(points[i][0], points[i][1], points[j][0], points[j][1]);
            insert(table, points[i], points[j], distanceSquared);
        }
    }

    int triangleCount;
    if (T == 1) {
        triangleCount = countIsoscelesTriangles(N, points, table);
    } else {
        triangleCount = countEquilateralTriangles(N, points, table);
    }

    printf("%d\n", triangleCount);

    destroyHashTable(table);
    free(points);

    return 0;
}

推荐答案

关于equilateral个三角形,我们可以缩短:因为所有的点都有整数坐标,没有等边三角形,如Equilateral triangle whose vertices are lattice points?所指出的,

要找到这isosceles个三角形,你可以采用以下方法:

对于每个点计数,可以创建多少个等腰三角形,其中该点是两条相等大小的边之间的连接,如下所示(每点):

  • 填充一个新的散列表,以距离为关键字,并使用相应的值来计算与当前点的距离处的点数.
  • 对于这个散列图中的每个计数,将Σ(Σ − 1)/2加到等腰三角形的总计数上.𝑘𝑘𝑘

假设散列表的添加和更新的平均时间复杂度为O(1),则总时间复杂度为O(2),其中n为输入点数.𝑛𝑛

C++相关问答推荐

如何将一个enum类型类型转换为另一个类型?

带双指针的2D数组

segfault在C中使用getline()函数

通过管道将一个子系统的标准输出发送到另一个子系统的标准输出

将指针作为参数传递给函数

如何将字符串argv[]赋给C中的整型数组?

核心转储文件中出现奇怪的大小变化

为什么GCC在每次循环迭代时都会生成一个数组的mov&S使用[]访问数组?(-03,x86)

如何在C客户端应用程序的ClientHello消息中添加自定义扩展?

正确的TCP/IP数据包 struct

Sizeof(&Q;字符串&Q;)的正确输出是什么?

在Rust和C之间使用ffi时如何通过 struct 中的[U8;1]成员传递指针

GCC奇怪的行为,有fork 和印花,有换行符和不换行符

C语言中的外部关键字

类型定义 struct 与简单的类型定义 struct

int * 指向int的哪个字节?

将非连续物理内存映射到用户空间

哪个首选包含第三个库S头文件?#INCLUDE;文件名或#INCLUDE<;文件名&>?

GDB 用内容初始化数组

当循环变量在溢出时未定义时,可以进行哪些优化?