코딩도장

가장 많은 직각삼각형이 만들어지는 둘레(≤ 1000)의 길이는?

출처 : http://euler.synap.co.kr/prob_detail.php?id=39

세 변의 길이가 모두 자연수 {a, b, c}인 직각삼각형의 둘레를 p 로 둘 때, p = 120 을 만족하는 직각삼각형은 아래와 같이 세 개가 있다.

{20, 48, 52}, {24, 45, 51}, {30, 40, 50}

1000 이하의 둘레 p에 대해서, 직각삼각형이 가장 많이 만들어지는 p의 값은 얼마인가?

수학

2014年05月14日 11:06

pahkey

(追記) (追記ここまで)
댓글 작성은 로그인이 필요합니다.
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

52개의 풀이가 있습니다. 1 / 6 Page

[Python]

import math
def Star(n):
 a = 0
 c = 0.0
 p =n/2
 _list = []
 while a < p:
 a += 1
 for b in range(a,p-a):
 c = math.sqrt(a*a + b*b)
 if c % 1 == 0:
 _list.append( a+b+c )
 return max(set(_list),key=_list.count)
print Star(1000)
print Star(10000)
840.0
5040.0

```

댓글 작성은 로그인이 필요합니다.
+1 10000 보다 작은 둘레 일 경우 3초 미만 걸리네요 - Starleaguer, 2014年05月15日 00:12 M D
굉장히 효율적인 알고리즘이네요! p을 변경하면서 a, b, c를 보는 것이 아니라 p를 넘지 않고 c가 정수인 경우의 a+b+c값을 정리해서 가장 많이 나온 a+b+c값을 출력하는 것이군요. 많이 배워갑니다. - 한 성탁, 2014年05月15日 09:42 M D
삼각형의 한 변의 길이는 둘레의 반 이상이 될 수 없다는 조건을 쓰신 것도 세심하시네요 - 한 성탁, 2014年05月15日 09:46 M D
+1 감사합니다. a+b > c 인 조건을 이용해서 a는 둘레의 반 이상이 될수없다고 대략적으로 계산한 알고리즘이에요^^; 최적화가 더 가능할거같은데 잘 떠오르지가 않네요 - Starleaguer, 2014年05月15日 09:53 M D
반대로생각하시다니 저의무지함이부끄럽습니다.. - 황 성호, 2014年07月25日 12:58 M D
+1 5040보다 9240이 더 많습니다. - *IDLE*, 2015年01月04日 16:37 M D
풀이가 잘못된 듯 합니다. def Star(n): a = 0 c = 0.0 p = int(n/2) _list = [] while a < p: a += 1 for b in range(1,p): c = math.sqrt(a*a + b*b) if c % 1 == 0: _list.append( a+b+c ) return max(set(_list),key=_list.count) 이렇게 하면 9240이 나옵니다. - Flair Sizz, 2016年06月28日 14:49 M D
b가 a보다 크고 p-a보다 작아야 할 필요는 없습니다. 1보다 크고 p보다 작기만 하면 됩니다. - Flair Sizz, 2016年06月28日 14:50 M D
range(a, p-a)에 수정이 필요한 것 같습니다. range(작은수, 큰수)되어야 올바르게 생성되는데, p-a가 a보다 작게 p-a<a 되는 경우에는 b 리스트가 생성되지 않아서 오류가 난 것 같습니다. ------------------------------------------------------------------ import math def Star(n): a = 0 c = 0.0 p =n/2 _list = [] while a < p: a += 1 blist = [a, p-a] blist.sort() for b in range(blist[0], blist[1]): c = math.sqrt(a*a + b*b) if c % 1 == 0: _list.append( a+b+c ) return max(set(_list),key=_list.count) print Star(1000) print Star(10000) ------------------------------------- 답 1000 : 840 10000 : 9240 - 조현우, 2017年02月25日 13:58 M D
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

포트란입니다 그냥 무식하게 반복문 돌렸습니다

출력은 둘레 840일 때 16가지 입니다만 a, b가 대칭인 경우를 생각해보면 8가지 같습니다

 program codingdojo451
 integer p, a, b, c, count, mcount, mnum
 mcount=0
 do p=3, 1000
 count=0
 do a=1, p-2
 do b=1, p-a-1
 c=p-a-b
 if(a**2 + b**2 .EQ. c**2) then
 count=count+1
 end if 
 end do 
 end do
 if(count .GT. mcount) then
 mcount=count
 mnum=p
 end if 
 end do
 print *,mcount,mnum
 pause
 end program codingdojo451

2014年05月14日 15:05

한 성탁

댓글 작성은 로그인이 필요합니다.
루프의 범위가 효율적이네요, 1000개씩 루프 세번 돌리면 무척 오래걸리더군요 ^^ - pahkey, 2014年05月14日 16:05 M D
+1 네.. 문제의 p=a+b+c라는 조건을 사용하였습니다. ^^ - 한 성탁, 2014年05月15日 09:26 M D
제가 착각했습니다 시간복잡도는 O(N^3)네요 - 한 성탁, 2014年05月15日 09:37 M D
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

직각삼각형의 다음과 같은 두가지 법칙을 이용하여 문제를 풀어 보았습니다.

  • 피타고라스의 정리 : a2+b2=c2
  • a, b, c 중 하나는 3의 배수여야한다.

python 2.7

import math
def right_triangle(n):
 found = []
 count = 0
 for a in range(3, n+1, 3):
 if a in found: continue
 for b in range(1, n+1-a):
 c = math.sqrt(a**2+b**2)
 if a+b+c == n:
 found+=[a,b,c]
 count+=1
 return count
m = -1
found = -1
for i in range(1, 1001):
 v = right_triangle(i)
 if v > m:
 m = v
 found = i
print found, m

대략 30초정도 걸리네요. 더 좋은 알고리즘을 연구해 봐야 할 것 같습니다.

댓글 작성은 로그인이 필요합니다.
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

세 변의 길이를 a,b,c라 하고 둘레를 p라 하면 a^2+b^2 = c a+b+c = p

이로부터 c = p-a-b이므로 a^2+b^2 = (p-a-b)

그런데 a^2+b^2 = ((a+b)^2 + (a-b)^2)/2

이로부터 2c^2 = (a+b)^2 + (a-b)^2 = (p-c)^2 + (p-c-2b)^2 이 식을 정리하면 c = - (2b^2 - 2bp - p^2) / (2b-2p)

a+b = p-c에 위의 c를 대입하면 a+b = (p^2 - 2b^2) / (2p-2b) b를 우변으로 이항하면 a = p(2b-p) / 2(b-p)

따라서 a,b,c를 모두 p와 b의 식으로 나타낼 수 있음.

따라서 루프는 p와 b에 대해서 두개만 돌리면 됨.

#include <stdio.h>
int main(void) {
 int p;
 int a, b, c;
 int max_p[2]={-1, -1};
 for(p=3; p <= 1000; ++p){
 int cnt = 0;
 for(b = p-1; b >= 0; --b){
 c = - ((2*b*b) - 2*(b*p) + p*p) / (2*(b - p));
 a = p*(2*b-p)/(2*(b-p));
 if(a > b) break;
 if(a>0 && c>0 && a+b+c == p){
 cnt++;
 }
 }
 if(cnt > max_p[1]) {
 max_p[0] = p;
 max_p[1] = cnt;
 }
 }
 printf("%d\n", max_p[0]);
 return 0;
}

2014年05月19日 20:34

Kim Jaeju

댓글 작성은 로그인이 필요합니다.
설명 첫 번째 줄에서 '세 변의 길이를 a,b,c라 하고 둘레를 p라 하면 a^2+b^2 = c a+b+c = p' 라고 하셨는데 두 변의 길이의 제곱의 합 a^2+b^2이 어떻게 다른 한 변의 길이 c와 같을 수가 있죠? c^2 이랑 같아야 하는 거 아닌가요? 그렇다면 그 아래의 모든 내용이 오류가 아닌지요. - ­박철희, 2021年09月26日 17:21 M D
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

[Python 2.7.3] 위에 좋은 알고리즘이 많아 약간 무식(?) 하지만 적절히 loop를 최소화하는 방법을 써보았습니다. 빗변 c는 a,b보다 작지않으며, 닮은꼴 삼각형을 배제시키기위해서 b 가 a보다 클때만 연산을 수행하면 중복 연산을 피할 수 있다고 생각했습니다. a+b+c가 1000 이상이면 c를 더 이상 진행 시킬 필요가 없고, b,c의 loop 시작 index를 아래 코드처럼 정의하면1000^3 보다는 훨씬 적은 횟수로 돌 수 있네요.

pp = [0]*1001
for a in range(1,1000) :
 for b in range(a,1000) :
 for c in range(b,1000) :
 _sum = a+b+c
 if _sum <= 1000 :
 if (c*c)==(a*a+b*b) :
 temp = pp[_sum]
 pp[_sum] = temp+1
 print "a,b,c = ",a,b,c
 print "pp and sum",pp[a+b+c], a+b+c
 else :
 break
temp = max(pp)
for i in range(1001) :
 if temp==pp[i] :
 print i,temp

제 노트북에서 18초 나오네요..

840 8

18.0680000782

댓글 작성은 로그인이 필요합니다.
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

C언어로 작성했습니다.

/*
사용한 조건:
a^2 + b^2 = c^2
a + b > c
그리고 a, b, c 중 하나는 반드시 3의 배수다.
여기서 둘레 p = a + b + c라고 한다면,
a^2 + b^2 = (p - a - b)^2
이고, 위의 식을 a에 대해 정리한다면,
a = (2bp - p^2) / 2(b-p) --- (1)
그리고 이 식과 p = a + b + c를 a + b > c에 대입하면
p(2b-p)/2(b-p) > p/2 - b
이고, 이 식을 정리하면
b(2b-p)<0
따라서 유효한 b의 범위는...
0 < b < p/2 --- (2)
그리고 여기서 이대로만 루프를 돌린다면 만일 p = 12인 경우
(a, b, c)의 집합이 (3, 4, 5), (4, 3, 5)가 나와 동일한 삼각형에 대해 중복 연산을 하게 되므로 쓸데없는 루프를 돌게 됩니다.
따라서 저는 a < b라는 조건을 추가했습니다.
a < b
위의 식에 (1) 식을 넣는다면
p(2b-p)/2(b-p) < b
위의 식을 정리하여 b의 범위를 구한다면
(2-2^0.5)p/2 < b < (2+2^0.5)p/2
가 나오는데, 이 때 (2)번 식에서 나타나는 b의 범위와 겹치는 부분만 따진다면
(2-2^0.5)p/2 < b < p/2 -- (3)
이 됩니다.
또한 a, b, c 중 하나는 반드시 3의 배수이므로, 가장 작은 3의 배수인 3을 포함하는 세 정수의 조합은
(3, 4, 5)이므로 p의 가능한 최소값은 3+4+5인 12가 됩니다.
따라서 저는 p는 12부터 1000까지 루프를 돌고, b는 (2-2^0.5)p/2 < b < p/2의 범 위내에서 루프를 돌게 했습니다.
Microsoft Visual Studio 2013로 작성했습니다.
*/
#include <stdio.h>
#include <math.h>
int main(void) {
 unsigned int threshold = 0;
 printf("Input the threshold : ");
 scanf_s("%u", &threshold); // MSVS 2013에서는 scanf를 쓰지 못하게 함.
 if (threshold == 0 || threshold < 12) {
 printf("Invalid value.");
 return -1;
 }
 unsigned int result[2] = { 0 };
 unsigned int loopCount = 0;
 float sqrt_2 = (float)sqrt(2);
 for (size_t p = 12; p <= threshold; p++) { 
 size_t b_limit = p / 2;
 if (p % 2 != 0) {
 b_limit++;
 }
 float b_limit_lower_llf = (2 - sqrt_2) / 2.0f * (float)p;
 size_t b_limit_lower = (size_t)b_limit_lower_llf;
 if (b_limit_lower < b_limit_lower_llf) {
 b_limit_lower++;
 }
 unsigned int match_count = 0;
 float llf_a = 0;
 size_t a = 0;
 for (size_t b = b_limit_lower; b < b_limit; b++) {
 llf_a = (float)p * (2 * (float)b - (float)p) / (2 * ((float)b - (float)p));
 a = (size_t)llf_a;
 if (llf_a == a) { 
 match_count++; 
 }
 loopCount++;
 }
 if (match_count > result[1]) {
 result[0] = p;
 result[1] = match_count;
 }
 }
 printf("Circumference with the most right triangles with integer sides = %u\n", result[0]);
 printf("Count of created triangles with the conditions = %u\n", result[1]);
 printf("Total loop count = %u\n", loopCount);
 return 0;
}
/* 수행 결과:
Input the threshold : 1000
Circumference with the most right triangles with integer sides = 840
Count of created triangles with the conditions = 8
Total loop count = 103396
계속하려면 아무 키나 누르십시오 . . .
*/

그래도 약간 마음에 들지 않아 다른 방법을 좀 찾아봤습니다. 이번에는 검색 방법 자체를 다르게 했습니다. 또한 더블 링크드 리스트를 썼기 때문에, C로 짠 버전도 있지만 너무 길어서 생략하고, C++에서 STL 라이브러리를 이용한 버전만 올립니다. 탐색에 사용한 방법은 아래의 링크에 있습니다. http://ko.wikipedia.org/wiki/피타고라스_수

//
// main.cpp
// CodingDoJang-451-CPP
//
// Created by Chrome-MBPR on 7/2/14.
// Copyright (c) 2014 cr2025x1. All rights reserved.
//
#include <iostream>
#include <list>
#include <cmath>
using namespace std;
struct PT {
 size_t a;
 size_t b;
 size_t c;
 bool primitive;
};
typedef struct PT PT;
class cPT_pair {
protected:
 size_t _p;
 list<PT> _pt_List;
public:
 const size_t &p;
 const list<PT> &pt_List;
 cPT_pair() : p(_p), pt_List(_pt_List) {
 setP(_p);
 }
 void setP(size_t p) {
 this->_p = p;
 }
 list<PT>* set_pt_List() {
 return &_pt_List;
 }
};
class cPT_pair_set : public list<cPT_pair*> {
public:
 virtual ~cPT_pair_set() {
 for (list<cPT_pair*>::iterator itr = this->begin(); itr != this->end(); advance(itr, 1)) {
 delete *itr;
 }
 }
};
void print_cPTList(list<cPT_pair*>* cPTList, bool primitive_mark);
int main(int argc, const char * argv[])
{
 size_t threshold = 0;
 cout << "Input the threshold: ";
 cin >> threshold;
 cout << "Searching primitive Pythagorean triples..." << endl;
 cPT_pair_set* cPTList = new cPT_pair_set;
 size_t loopCount_1st = 0;
 // 짝수인 p만이 자연수인 피타고라스 수의 합이 될 수 있다. (p = 2m^2 + 2mn)
 for (size_t p = 12; p <= threshold; p += 2) {
 // a^2 + b^2 = c^2이고 서로소인 (a, b, c)는 아래와 같이 m, n을 통해 표현할 수 있다.
 // a = m^2 - n^2
 // b = 2mn
 // c = 2m^2 - n^2
 // m>n, m, n은 자연수, m+n은 홀수
 //
 // p = a + b + c
 // = 2m^2 + 2mn
 // n = p/(2m) - m
 // n은 자연수이므로 p/(2m)-m > 0, 식을 정리하면
 // -(p/2)^0.5 < m < (p/2)^0.5
 // 또한 m > n이므로 p/(2m)-m < m, 식을 정리하면
 // m < -p^0.5/2 or m > p^0.5/2
 // 두 범위의 교차부분은 0.5p^0.5 < m < (p/2)^0.5
 //
 // 즉 m은 저 범위 내에서 루프를 돌린다.
 // 이렇게 만들어진 a, b, c는 원시 피타고라스 수가 된다.
 // 원시 피타고라스 수: a, b, c의 최대공약수가 1인 피타고라스 수. ex. (3, 4, 5), (5, 12, 13), 
 size_t m_LowerBound = (size_t)floor((pow(p, 0.5f) / 2.0f));
 size_t m_UpperBound = (size_t)ceil(pow(p / 2.0f, 0.5f));
 size_t n = 0;
 for (size_t m = m_LowerBound + 1; m < m_UpperBound; m++) {
 loopCount_1st++;
 if (p % (2 * m) != 0) {
 // n이 자연수가 될 수 없음.
 continue;
 }
 n = p / (2 * m) - m;
 if ((m + n) % 2 == 0) {
 // m + n이 홀수가 아니다.
 continue;
 }
 if ((m > 1 && n > 1) && (m % n == 0 || n % m == 0)) {
 // m과 n이 서로소가 아니다.
 continue;
 }
 size_t m_2 = m * m;
 size_t n_2 = n * n;
 size_t a = m_2 - n_2;
 size_t b = 2 * m * n;
 size_t c = m_2 + n_2;
 PT newPT;
 newPT.a = a;
 newPT.b = b;
 newPT.c = c;
 newPT.primitive = true;
 unsigned char isNewNodeNeeded = 1;
 list<cPT_pair*>::iterator lastNode = cPTList->end();
 advance(lastNode, -1);
 if (cPTList->size() > 0) {
 cPT_pair* last_cPT_pair = *lastNode;
 if (last_cPT_pair->p == p) {
 isNewNodeNeeded = 0;
 last_cPT_pair->set_pt_List()->push_back(newPT);
 }
 }
 if (isNewNodeNeeded) {
 cPT_pair* new_cPT_pair = new cPT_pair;
 new_cPT_pair->setP(p);
 new_cPT_pair->set_pt_List()->push_back(newPT);
 cPTList->push_back(new_cPT_pair);
 }
 }
 }
 // 찾아낸 원시 피타고라수 수들을 출력
 cout << "Printing found primitive Pythagorean triples..." << endl;
 cout << "p : circumference of the right triangle" << endl;
 print_cPTList(cPTList, false);
 size_t cPT_pair_listCount = cPTList->size();
 cout << "Total count of found p with Pythagorean triples = " << cPT_pair_listCount << endl;
 cout << "Total loop count during the search for primitive Pythagorean triples = " << loopCount_1st << endl;
 // 원시형이 아닌 피타고라스 수에 대한 탐색
 cout << "Searching and adding non-primitive Pythagorean triples..." << endl;
 size_t loopCount_2nd = 0;
 size_t maxP[2] = { 0 }; // [0] = 현재까지 가장 많은 피타고라스 수를 가지는 p, [1] = [0]에 있는 p가 가진 피타고라스 수 세트의 개수
 size_t p_threshold = threshold;
 // p의 초기 값을 짝수로 짜맞춘다.
 if (p_threshold % 2 != 0) {
 p_threshold--;
 }
 // 위에서 구한 원시 피타고라스 수를 가지고 있는 링크드 어레이에 원시형이 아닌 피타고라스 수들을 추가시킨다.
 list<cPT_pair*>::iterator insertionPoint = cPTList->end();
 advance(insertionPoint, -1);
 size_t foundCount = 0;
 for (size_t p = p_threshold; p >= 12; p -= 2) {
 foundCount = 0;
 // 삽입 지점(insertion point)을 항상 현재 p보다 높은 값과 낮은 값끼리의 경계점에 둔다. 만일 현재 p와 같은 값을 가진 노드가 있다면 그 노드를 삽입지점으로 고르며, 없다면 현재 p보다 작은 값 중 가장 큰 값을 가지는 노드를 고른다.
 // 위의 알고리즘 결과로 나오는 리스트의 각 노드의 p는 앞에서 뒤로 오름차순이다.
 while ((*insertionPoint)->p > p) {
 advance(insertionPoint, -1);
 }
 // 삽입 지점 노드를 기준으로, 앞쪽을 향해 노드들을 순차적으로 읽어나가 노드의 p값을 비교한다.
 // 삽입 지점 노드와 그 앞의 노드들은 모두 모두 원시 피타고라스 수만을 담고 있다.
 list<cPT_pair*>::iterator current_cPT_pairNode = insertionPoint;
 bool isWritingNodeDecided = false;
 list<cPT_pair*>::iterator writingNode;
 list<PT>* writingPTList = nullptr;
 while (1) {
 isWritingNodeDecided = false;
 cPT_pair* current_cPT_pair = *current_cPT_pairNode;
 loopCount_2nd++;
 // 원시 피타고라스 수를 가지는 둘레값이 현재 p값의 약수라면, 현재 p값을 둘레값으로 나눈 값을 원시 피타고라스 수에 곱한다면 현재 p값을 둘레로 가지는 피타고라스 수(원시는 아닌)가 나온다.
 if (p % current_cPT_pair->p == 0) {
 size_t commonDivisor = p / current_cPT_pair->p;
 if (commonDivisor == 1) {
 // 1배수다 == 현재 검사 중인 노드의 p값과 현재 p값은 같다. 이 때는 아래의 작업을 할 경우 기존 값과 중복되는 똑같은 값이 추가 저장되므로, 값을 추가 저장하는 아래의 작업을 하면 안 된다.
 foundCount++;
 }
 else {
 if (isWritingNodeDecided == false) {
 isWritingNodeDecided = true;
 // 삽입지점에 현재의 p값을 가진 노드가 있다. 노드를 추가 삽입할 필요성이 없으므로 이 노드를 그대로 활용한다.
 if ((*insertionPoint)->p == p) {
 writingNode = insertionPoint;
 }
 else {
 // 현재의 p값을 가지는 노드가 없으므로, 노드를 삽입지점의 뒷편에 추가 삽입한다.
 cPT_pair* new_cPT_pair = new cPT_pair;
 new_cPT_pair->setP(p);
 writingNode = insertionPoint;
 advance(writingNode, 1);
 cPTList->insert(writingNode, new_cPT_pair);
 advance(writingNode, -1);
 }
 writingPTList = (*writingNode)->set_pt_List();
 }
 // 현재 읽어들인 노드가 가지고 있는 원시 피타고라스 수 세트에 구해둔 배수를 곱해 현재 p값을 둘레로 가지는 비원시 피타고라스 수 세트를 만들어 현재 p값을 가지고 있는 기록 중인 노드의 하위 링크드 리스트에 추가한다.
 const list<PT>& currentPTList = current_cPT_pair->pt_List;
 for (list<PT>::const_iterator currentPTNode = currentPTList.cbegin();
 currentPTNode != currentPTList.cend();
 advance(currentPTNode, 1)) {
 PT currentPT = *currentPTNode;
 PT newPT;
 newPT.a = currentPT.a * commonDivisor;
 newPT.b = currentPT.b * commonDivisor;
 newPT.c = currentPT.c * commonDivisor;
 newPT.primitive = 0;
 writingPTList->push_back(newPT);
 foundCount++;
 }
 }
 }
 // 읽어낸 노드의 바로 앞 노드를 지정한다. 위에서 삽입한 노드들은 모두 삽입지점의 뒤에 추가되었다.
 // 따라서 그 어떤 루프도 이전 루프에서 추가한 비원시 피타고라스 수가 담긴 노드를 접근하게 되는 비효율적인 경우가 생기지 않는다.
 if (current_cPT_pairNode == cPTList->begin()) {
 // 맨 앞 노드임을 의미하므로, 현재 p값에 대한 작업을 중지한다.
 break;
 }
 else {
 advance(current_cPT_pairNode, -1);
 }
 }
 // 가장 많은 피타고라스 수를 가진 둘레값을 현재 값과 비교해 저장
 if (maxP[1] < foundCount) {
 maxP[0] = p;
 maxP[1] = foundCount;
 }
 }
 cout << "Printing found entire Pythagorean triples..." << endl;
 cout << "p : circumference of the right triangle" << endl;
 print_cPTList(cPTList, 1);
 cout << "Total loop count during the search for all Pythagorean triples = " << loopCount_2nd << endl;
 cout << "Circumference P with the most Pythagorean triples = " << maxP[0] << "(" << maxP[1] << " sets)" << endl;
 cout << "Total loop during entire operations = " << loopCount_1st + loopCount_2nd << endl;
 delete cPTList;
 return 0;
}
void print_cPTList(list<cPT_pair*>* cPTList, bool primitive_mark) {
 for (list<cPT_pair*>::iterator current_cPT_pairNode = cPTList->begin();
 current_cPT_pairNode != cPTList->end();
 advance(current_cPT_pairNode, 1)) {
 cPT_pair* current_cPT_pair = *current_cPT_pairNode;
 const list<PT>& currentPTList = current_cPT_pair->pt_List;
 for (list<PT>::const_iterator currentPTNode = currentPTList.cbegin();
 currentPTNode != currentPTList.cend();
 advance(currentPTNode, 1)) {
 cout << "p = " << current_cPT_pair->p << ", (a, b, c) = (" << currentPTNode->a << ", " << currentPTNode->b << ", " << currentPTNode->c << ")";
 if (currentPTNode->primitive && primitive_mark) {
 cout << " (primitive)";
 }
 cout << endl;
 }
 }
}
/*
실행결과:
Input the threshold: 1000
Searching primitive Pythagorean triples...
Printing found primitive Pythagorean triples...
p : circumference of the right triangle
(중략)
Total count of found p with Pythagorean triples = 75
Total loop count during the search for primitive Pythagorean triples = 2169
Searching and adding non-primitive Pythagorean triples...
Printing found entire Pythagorean triples...
p : circumference of the right triangle
(중략)
p = 840, (a, b, c) = (399, 40, 401) (primitive)
p = 840, (a, b, c) = (390, 56, 394)
p = 840, (a, b, c) = (350, 120, 370)
p = 840, (a, b, c) = (252, 240, 348)
p = 840, (a, b, c) = (105, 360, 375)
p = 840, (a, b, c) = (315, 168, 357)
p = 840, (a, b, c) = (140, 336, 364)
p = 840, (a, b, c) = (210, 280, 350)
(중략)
Total loop count during the search for all Pythagorean triples = 18409
Circumference P with the most Pythagorean triples = 840(8 sets)
Total loop during entire operations = 20578
Program ended with exit code: 0
*/

최대한 더블 링크드 리스트의 장점을 살려서 썼습니다. 복사 작업 등을 제외하고 조건에 맞는 숫자를 찾기 위해 도는 루프의 수를 이번에는 20578회로 줄일 수 있었습니다. 2013년 후기형 맥북 프로 레티나 15인치 기준으로 거의 시작 직후에 답이 나오네요.

Xcode 5.1.1로 작성하였습니다.

댓글 작성은 로그인이 필요합니다.
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.
  1. len = a + b + c
  2. a^2 + b^2 = c^2
  3. b = (len^2 - 2lena) / (2*(len-a))
#python 3.2.5
def calc_c(a, b):
 assert(a > 0)
 if b < a:
 return False
 assert(a <= b)
 sq = a*a + b*b
 sqa = a**a
 for c in range(a, sq):
 if sq == c*c:
 return c
 return False
def calc_b(L, a):
 numerator = L*L - 2*L*a
 if numerator < 0: return False
 denominator = 2 * (L - a)
 if 0 == numerator % denominator:
 return numerator//denominator
 return False
def abr(L):
 rt = []
 hL = (L // 2) * 2
 for a in range(1, hL):
 b = calc_b(L, a)
 if not b: continue
 c = calc_c(a, b)
 if not c: continue
 #yield a
 rt.append((a, b, c))
 return rt
def main():
 rt = dict(len=1, lst=[])
 L = 0
 for l in range(1, 1001):
 tmp = abr(l)
 if len(tmp) > L:
 L = len(tmp)
 rt['len'] = l
 rt['lst'] = tmp
 print(L, rt['len'], rt['lst'])
'''
8
840
[(40, 399, 401), (56, 390, 394), (105, 360, 375), (120, 350, 370), (140, 336, 364), (168, 315, 357), (210, 280, 350), (240, 252, 348)]
'''
댓글 작성은 로그인이 필요합니다.
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

python 2.7.8

angle_tri = list()
def is_angle_tri(length_list):
 left_clause = 0
 right_clause = 0
 max_num = max(length_list)
 max_num_index = length_list.index(max_num)
 for i in range(3):
 if i == max_num_index:
 left_clause = length_list[i] ** 2
 else:
 right_clause += length_list[i] ** 2
 if left_clause == right_clause:
 return True
 return False
def is_duple(length_list):
 if set(length_list) in map(set,angle_tri):
 return True
 return False
maxv = 0
max_n = 0
for n in range(3,1001):
 angle_tri = list()
 for i in range(1,n+1):
 for j in range(1,n+1):
 if is_angle_tri([i,j,n-i-j]) and not is_duple([i,j,n-i-j]):
 angle_tri.append([i,j,n-i-j])
 print n
 if maxv < len(angle_tri):
 maxv = len(angle_tri)
 max_n = n
 print 'max = %d' % max_n

1부터 p 까지 i와 j의 이중 반복문을돌려서 계산했습니다. i와 j가 정해졌다면 나머지 한숫자는 자연스럽게 p-i-j 이기때문에 이중반복문을 사용하였습니다. 근데 좀 오래걸리는군요.. 더좋은알고리즘이 분명있을텐데말이죠..흠 생각해봐야겠군요 어쨋든 답은 840입니다.

댓글 작성은 로그인이 필요합니다.
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.
def tri(abc):
 if abc[2]*abc[2] == abc[0]*abc[0] + abc[1]*abc[1] :
 return True
 else :
 return False
def max_tri(num):
 data = []
 answer = []
 for i in range(1, num):
 for j in range(i, int(num/2)):
 k = num - i - j
 data = [i, j, k]
 data = sorted(data)
 if (tri(data)) & (data not in answer):
 answer.append(data)
 return len(answer)
max_nm = 0
final = 0
for i in range(3, 1001):
 tmp = max_tri(i)
 if max_nm < tmp :
 max_nm = tmp
 final = i
print (final) 

2014年08月21日 01:17

superarchi

댓글 작성은 로그인이 필요합니다.
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

Java 사용. 맨위 답이 정말 소름끼치내요.. 많이 배워갑니다. 결과 값 둘레는 840 이며 개수는 8 Roop = 16099676

/*
 세 변의 길이가 모두 자연수 {a, b, c}인 직각삼각형의 둘레를 p 로 둘 때, p = 120 을 만족하는 직각삼각형은
 아래와 같이 세 개가 있다.
 {20, 48, 52}, {24, 45, 51}, {30, 40, 50}
 1000 이하의 둘레 p에 대해서, 직각삼각형이 가장 많이 만들어지는 p의 값은 얼마인가?
 */
public class Fifth {
 //A^2 + B^2 = C^2
 //A+B > C
 //A+B+C < 1000
 /*
 삼각형을 만드는 조건 (A< B <C)
 A+B > C 이기 때문에
 C+C < A+B+C < C+C+C
 @ 2C < A+B+C < 3C 이고 A+B+C = P 이므로
 P/3 < C < P/2 이다.
 */
 public static void main(String[] args){
 int A,B,C,P;
 int roopCount = 0;
 int resultP = 0;
 int resultN = 0;
 for(P=3; P< 1000; P++){
 int number = 0;
 for(C = P/3+1; C < (int)Math.ceil(((double)P/2.0));C=C+1){
 for(A = 1; A<= (P-C)/2; A++){
 B = P-C-A;
 if(A*A + B*B == C*C && B >= A){
 number++;
 }
 roopCount++;
 }
 }
 if(resultN < number){
 resultP = P;
 resultN = number;
 }
 }
 System.out.println("결과 값 둘레는 " + resultP + " 이며 개수는 " + resultN);
 System.out.println("Roop = " + roopCount);
 }
}
댓글 작성은 로그인이 필요합니다.
(注記) 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

풀이 작성

(注記) 풀이작성 안내
  • 본문에 코드를 삽입할 경우 에디터 우측 상단의 "코드삽입" 버튼을 이용 해 주세요.
  • 마크다운 문법으로 본문을 작성 해 주세요.
  • 풀이를 읽는 사람들을 위하여 풀이에 대한 설명도 부탁드려요. (아이디어나 사용한 알고리즘 또는 참고한 자료등)
  • 작성한 풀이는 다른 사람(빨간띠 이상)에 의해서 내용이 개선될 수 있습니다.
풀이 작성은 로그인이 필요합니다.
목록으로
코딩도장

코딩도장은 프로그래밍 문제풀이를 통해서 코딩 실력을 수련(Practice)하는 곳입니다.

수학 x 6
연관 문제

언어별 풀이 현황
전 체 x 52
python x 29
기 타 x 5
cpp x 5
java x 7
perl x 1
delphi x 1
ruby x 1
cs x 2
matlab x 1
코딩도장 © 2014 · 문의 [email protected]
피드백 · 개인정보취급방침 · RSS

AltStyle によって変換されたページ (->オリジナル) /