查找原始毕达哥拉斯三元组的算法

时间:2012-09-13 08:10:49

标签: primes primitive pythagorean

这是我的代码:

// PPT.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

#define LOWER_BOUND 1
#define UPPER_BOUND 20

struct ppt
{
    int v1;
    int v2;
    int v3;
    ppt *next;
};

typedef struct ppt PPT;
typedef PPT *ppt_ptr;


void insert_ppt(ppt_ptr *h_ptr, ppt_ptr *t_ptr, int u1, int u2, int u3);

void print_ppt(ppt_ptr curr_ptr);

int is_prime(int n);

int is_pythagorean_triplet(int v1, int v2, int v3);

int different_triples(int v1, int v2, int v3,  int u1, int u2, int u3);  

int are_exact_multiples(int p, int q, int r,  int l, int m, int n);  

int is_unique_and_insertable(ppt_ptr curr_ptr, int v1, int v2, int v3);  

//====================================================================

int _tmain(int argc, _TCHAR* argv[])
{
    ppt_ptr head_ptr = NULL;
    ppt_ptr tail_ptr = NULL;

    for (int a = LOWER_BOUND;  a <= UPPER_BOUND; a++)
    {
        for (int b = LOWER_BOUND;  b <= UPPER_BOUND;  b++)
        {
            for (int c = LOWER_BOUND;  c <= UPPER_BOUND; c++)
            {
                if(is_pythagorean_triplet(a,b,c) == 1)
                {
                    if(head_ptr == NULL)
                    {
                        //printf("%d %d %d",a,b,c);
                        insert_ppt(&head_ptr,&tail_ptr,a,b,c);
                    }
                    //printf("%d %d %d",a,b,c);
                    if(is_unique_and_insertable(tail_ptr,a,b,c) == 1)
                    {   
                        //printf("%d %d %d\n",a,b,c);
                        insert_ppt(&head_ptr,&tail_ptr,a,b,c);
                    }
                }
            }
        }
    }

    //print_ppt(head_ptr);
    getchar();
    getchar();
    return 0;
}

此函数在列表末尾插入新节点

void insert_ppt(ppt_ptr *h_ptr, ppt_ptr *t_ptr, int u1, int u2, int u3)
{
    ppt_ptr new_ptr;

    new_ptr = ppt_ptr( malloc( sizeof(PPT) ) );

    if(new_ptr != NULL)
    {
        new_ptr->v1   = u1;
        new_ptr->v2   = u2;
        new_ptr->v3   = u3;
        new_ptr->next = NULL;

        if(*h_ptr == NULL)
        {
            *h_ptr = new_ptr;
        }
        else
        {
            (*t_ptr)->next = new_ptr;
        }

        *t_ptr = new_ptr;
    }
    else
    {
        printf("%d %d %d not inserted. No memory available.\n",u1,u2,u3);
    }
}

此功能打印列表

void print_ppt(ppt_ptr curr_ptr)
{
    if(curr_ptr == NULL)
    {
        printf("List is empty.\n\n");
    }
    else
    {
        while(curr_ptr != NULL)
        {
            printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
            curr_ptr = curr_ptr->next;
        }
    }
}

此函数确定数字是否为素数

// Function 1
int is_prime(int n)
{
    int num_of_factors = 0;
    int i = 1;

    for (i=1; i<=n; i++)
    {
        if (n % i  == 0)
        {
            num_of_factors ++;
        }
    }

    if (num_of_factors == 2)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

此函数确定三联体是否为毕达哥拉斯

// Function 2
int is_pythagorean_triplet(int v1, int v2, int v3)
{
    if ( (v1*v1 + v2*v2 == v3*v3) || (v2*v2 + v3*v3 == v1*v1) || (v1*v1 + v3*v3 == v2*v2) )
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

此函数确定三元组是否唯一,这是我遇到问题的函数

int is_unique_and_insertable(ppt_ptr curr_ptr, int v1, int v2, int v3)
{
    if(curr_ptr == NULL)
    {
        //printf("List is empty.\n\n");
    }
    else
    {
        if(curr_ptr != NULL)
        {
            //printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
            int u1 = curr_ptr->v1;
            int u2 = curr_ptr->v2;
            int u3 = curr_ptr->v3;

            if( (different_triples(v1,v2,v3,u1,u2,u3)) && 
                (!are_exact_multiples(v1,v2,v3,u1,u2,u3) ) )
            {
                printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
                return 1;
            }

            //printf("yoyoyo");
            curr_ptr = curr_ptr->next;
        }
    }
    return 0;
}

此函数确定三元组是否唯一

// Definition:  This function checks if <v1,v2,v3> and <u1,u2,u3> are different triplets
//              or not.  If they are different triplets, it returns 1.
int different_triples(int v1, int v2, int v3,  int u1, int u2, int u3)
{
    if (v1==u1 && v2==u2 &&  v3==u3)
        return 0;
    else if (v1==u1 && v2==u3 && v3==u2)
        return 0;
    else if (v1==u2 && v2==u1 && v3==u3)
        return 0;
    else if (v1==u2 && v2==u3 && v3==u1)
        return
    else if (v1==u3 && v2==u2 && v3==u1)
        return 0;
    else if (v1==u3 && v2==u1 && v3==u2)
        return 0;
    else
        return 1;
}

此函数确定三元组是否是三元组的倍数

// This function tests if the triplet <p,q,r> is an exact multiple of <l,m,n> in any order
//   (arrangement/permutation)
int  are_exact_multiples(int v1, int v2, int v3,  int u1, int u2, int u3)
{
    if (v1%u1==0 && v2%u2==0 &&  v3%u3==0)
        return 1;
    else if (u1%v1==0 && u2%v2==0 &&  u3%v3==0)
        return 1;
    else if (v1%u1==0 && v2%u3==0 && v3%u2==0)
        return 1;
    else if (u1%v1==0 && u2%v3==0 && u3%v2==0)
        return 1;
    else if (v1%u2==0 && v2%u1==0 && v3%u3==0)
        return 1;
    else if (v1%u2==0 && v2%u3==0 && v3%u1==0)
        return 1;
    else if (u1%v2==0 && u2%v1==0 && u3%v3==0)
        return 1;
    else if (u1%v2==0 && u2%v3==0 && u3%v1==0)
        return 1;
    else if (v1%u3==0 && v2%u2==0 && v3%u1==0)
        return 1;
    else if (v1%u3==0 && v2%u1==0 && v3%u2==0)
        return 1;
    else if (u1%v3==0 && u2%v2==0 && u3%v1==0)
        return 1;
    else if (u1%v3==0 && u2%v1==0 && u3%v2==0)
        return 1;
    else
        return 0;
}

我知道算法没有优化......我稍后会这样做。有人可以帮我把这段代码搞定。

1 个答案:

答案 0 :(得分:0)

你的函数is_unique_and_insertable可能应检查列表中是否已存在等效的三元组(不同顺序的相同数字),或者新的三元组是列表中三元组的倍数(模数排列)。但它只是将新的三元组与第一个列表元素进行比较,函数中没有循环语句或递归。

int is_unique_and_insertable(ppt_ptr curr_ptr, int v1, int v2, int v3)
{
    if(curr_ptr == NULL)
    {
        //printf("List is empty.\n\n");
    }
    else
    {
        if(curr_ptr != NULL)
        {
            //printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
            int u1 = curr_ptr->v1;
            int u2 = curr_ptr->v2;
            int u3 = curr_ptr->v3;

            if( (different_triples(v1,v2,v3,u1,u2,u3)) && 
                (!are_exact_multiples(v1,v2,v3,u1,u2,u3) ) )
            {
                printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
                return 1;
            }

            //printf("yoyoyo");
            curr_ptr = curr_ptr->next;
        }
    }
    return 0;
}

如果使用while(curr_ptr != NULL),您可以将其与第一个元素进行比较。但是,它仍然会有错误的逻辑,只要它找到一个不同的三元组,它就会返回true(1),而新的不是三倍。

逻辑必须反过来,如果遇到等效的三元组(或者新的三元组是三倍),那么只有在遍历整个列表而没有遇到这样的情况时才返回false(0)。三重你应该回归真实:

int is_unique_and_insertable(ppt_ptr curr_ptr, int v1, int v2, int v3)
{
    while(curr_ptr != NULL)
    {
        int u1 = curr_ptr->v1;
        int u2 = curr_ptr->v2;
        int u3 = curr_ptr->v3;
        if (!different_triples(v1, v2, v3, u1, u2, u3) || are_exact_multiples(v1, v2, v3, u1, u2, u3))
        {
            return 0;
        }
        curr_ptr = curr_ptr->next;
    }
    return 1;
}

这会让您更接近正确的计划,但您的are_exact_multiples功能有问题,它会将(15, 36, 39)声明为(3, 4, 5)的倍数,尽管它不是。{0}。

如果你只考虑三(a, b, c) a <= b <= c(实际上是a < b < c,因为毕达哥拉斯三重奏不能拥有三重奏,你会得到一个更简单,更容易合适的程序两个相等的组成部分)。

你说你以后会对待效率,但请尽快这样做,你的is_prime功能效率很低。你应该在找到第一个非平凡的除数后立即停止,并且当你到达平方根时就可以停止:

int is_prime(int n)
{
    if (n < 2) return 0;
    if (n%2 == 0) return n == 2;
    for(int d = 3; d*d <= n; d += 2)
    {
        if (n%d == 0) return 0;
    }
    return 1;
}