<< problem 278 - Linear Combinations of Semiprimes | Ant and seeds - problem 280 >> |
Problem 279: Triangles with integral sides and an integral angle
(see projecteuler.net/problem=279)
How many triangles are there with integral sides, at least one integral angle (measured in degrees), and a perimeter that does not exceed 10^8 ?
My Algorithm
Niven's theorem (see en.wikipedia.org/wiki/Niven's_theorem) states that for rational angles sin(alpha) the only rational values are \{ 0, +1/2, -1/2, +1, -1 \}.
Since sin(90 + alpha) = cos(alpha) this theorem can be applied to cos(alpha), too.
Thus only 3 angles can be part of a valid triangle:
(1) cos( 60) = +1/2
(2) cos( 90) = 0
(3) cos(120) = -1/2
Each triangle satisfies (see en.wikipedia.org/wiki/Law_of_cosines):
(4) c^2 = a^2 + b^2 - 2ab cos(gamma)
If gamma = 60 then (4) can be simplified to
(5) c^2 = a^2 + b^2 - ab
If gamma = 90 then (4) can be simplified to
(6) c^2 = a^2 + b^2
If gamma = 120 then (4) can be simplified to
(7) c^2 = a^2 + b^2 + ab.
These equations have their own Wikipedia pages, too: en.wikipedia.org/wiki/Eisenstein_triple and en.wikipedia.org/wiki/Pythagorean_triple .
But more interesting is en.wikipedia.org/wiki/Integer_triangle which gives away nice formulas to generate all such triangles.
The formulas need two variables m and n where 0 < n < m.
The case cos(60) boils down to:
a = m^2 - mn + n^2
b = 2mn - n^2
c = m^2 - n^2
I solved cos(90) in problem 75 (see en.wikipedia.org/wiki/Pythagorean_triple):
a = m^2 - n^2
b = 2mn
c = m^2 + n^2
And finally cos(120):
a = m^2 + mn + n^2
b = 2mn + n^2
c = m^2 - n^2
The triples (a,b,c) are not necessarily basic triples - but their greatest common divisor is always either 1 or 3.
Now I have all the tools to generate all basic triples. Those basic triples and all their multiples are solutions.
There are 10^8 / perimeter multiples of each basic triples which satisfy the condition that the perimeter must not exceed 10^8.
The functions search60()
, search90()
and search120()
implement each set of equations for 60, 90 and 120.
Note
Fortunately I didn't find a triangle with angles 60 + 90 + 30 and integer sides.
If there were any, I would have needed to avoid double-counting (as they would be counted as 60 and 90 separately).
Since today is my lucky day, I added a few OpenMP pragmas which reduce the execution time from 4 to less than 1 second on my computer (enable #define PARALLEL
).
Interactive test
You can submit your own input to my program and it will be instantly processed at my server:
This is equivalent toecho 100 | ./279
Output:
Note: the original problem's input 100000000
cannot be entered
because just copying results is a soft skill reserved for idiots.
(this interactive test is still under development, computations will be aborted after one second)
My code
… was written in C++11 and can be compiled with G++, Clang++, Visual C++. You can download it, too. Or just jump to my GitHub repository.
#include <iostream>
#include <cmath>
#define PARALLEL
const auto numCores = 8; // 4 = four cores, 8 = eight cores, etc.
// ---------- code copied from my toolbox ----------
// find greatest common divisor
template <typename T>
T gcd(T a, T b)
{
while (a != 0)
{
T c = a;
a = b % a;
b = c;
}
return b;
}
// ---------- problem-specific code ----------
// 90 degrees (based on code from problem 75)
unsigned int search90(unsigned int limit)
{
unsigned int result = 0;
unsigned int last = sqrt(limit / 2);
#ifdef PARALLEL
#pragma omp parallel for num_threads(numCores) reduction(+:result) schedule(dynamic)
#endif
for (unsigned int m = 2; m < last; m++)
for (unsigned int n = (m & 1) + 1; n < m; n += 2) // m + n must be odd
{
// only valid m and n
if (gcd(m, n) != 1)
continue;
// compute basic triplet
auto a = m*m - n*n;
auto b = 2*m*n;
auto c = m*m + n*n;
// too large ?
auto sum = a + b + c;
if (sum > limit)
break;
// all its multiples are valid, too
auto numMultiples = limit / sum;
result += numMultiples;
}
return result;
}
// 60 degrees
unsigned int search60(unsigned int limit)
{
unsigned int last = sqrt(limit*3/2);
unsigned int result = 0;
#ifdef PARALLEL
#pragma omp parallel for num_threads(numCores) reduction(+:result) schedule(dynamic)
#endif
for (unsigned int m = 2; m < last; m++)
for (unsigned int n = 1; 2*n <= m; n++)
{
// only valid m and n
if (gcd(m, n) != 1)
continue;
// compute next triplet
auto a = m*m - m*n + n*n;
auto b = 2*m*n - n*n;
auto c = m*m - n*n;
auto sum = a + b + c;
// divide by their greatest common divisor to get the basic triplet
// gcd(a,b,c) is either 1 or 3
if (a % 3 == 0 && b % 3 == 0 && c % 3 == 0)
sum /= 3;
if (sum > 3*limit)
break;
if (sum <= limit)
{
// all its multiples are valid, too
auto numMultiples = limit / sum;
result += numMultiples;
}
}
return result;
}
// 120 degrees
unsigned int search120(unsigned int limit)
{
unsigned int result = 0;
unsigned int last = sqrt(limit*3/2);
#ifdef PARALLEL
#pragma omp parallel for num_threads(numCores) reduction(+:result) schedule(dynamic)
#endif
for (unsigned int m = 2; m < last; m++)
for (unsigned int n = 1; 2*n <= m; n++)
{
// only valid m and n
if (gcd(m, n) != 1)
continue;
// compute next triplet
auto a = m*m + m*n + n*n;
auto b = 2*m*n + n*n;
auto c = m*m - n*n;
// skip mirrored triangles
if (b > c)
break;
// note: a is always the longest side
auto sum = a + b + c;
// divide by their greatest common divisor to get the basic triplet
// gcd(a,b,c) is either 1 or 3
if (a % 3 == 0 && b % 3 == 0 && c % 3 == 0)
sum /= 3;
if (sum > 3*limit)
break;
// all its multiples are valid, too
auto numMultiples = limit / sum;
result += numMultiples;
}
return result;
}
int main()
{
unsigned int limit = 100000000;
std::cin >> limit;
auto num60 = search60 (limit);
auto num90 = search90 (limit);
auto num120 = search120(limit);
auto result = num60 + num90 + num120;
std::cout << result << std::endl;
return 0;
}
This solution contains 25 empty lines, 22 comments and 12 preprocessor commands.
Benchmark
The correct solution to the original Project Euler problem was found in 3.9 seconds.
The code can be accelerated with OpenMP but the timings refer to the single-threaded version on an Intel® Core™ i7-2600K CPU @ 3.40GHz.
(compiled for x86_64 / Linux, GCC flags: -O3 -march=native -fno-exceptions -fno-rtti -std=gnu++11 -DORIGINAL
)
See here for a comparison of all solutions.
Note: interactive tests run on a weaker (=slower) computer. Some interactive tests are compiled without -DORIGINAL
.
Changelog
December 27, 2017 submitted solution
December 27, 2017 added comments
Difficulty
Project Euler ranks this problem at 60% (out of 100%).
Links
projecteuler.net/thread=279 - the best forum on the subject (note: you have to submit the correct solution first)
Code in various languages:
Python github.com/Meng-Gen/ProjectEuler/blob/master/279.py (written by Meng-Gen Tsai)
C++ github.com/roosephu/project-euler/blob/master/279.cpp (written by Yuping Luo)
Those links are just an unordered selection of source code I found with a semi-automatic search script on Google/Bing/GitHub/whatever.
You will probably stumble upon better solutions when searching on your own.
Maybe not all linked resources produce the correct result and/or exceed time/memory limits.
Heatmap
Please click on a problem's number to open my solution to that problem:
green | solutions solve the original Project Euler problem and have a perfect score of 100% at Hackerrank, too | |
yellow | solutions score less than 100% at Hackerrank (but still solve the original problem easily) | |
gray | problems are already solved but I haven't published my solution yet | |
blue | solutions are relevant for Project Euler only: there wasn't a Hackerrank version of it (at the time I solved it) or it differed too much | |
orange | problems are solved but exceed the time limit of one minute or the memory limit of 256 MByte | |
red | problems are not solved yet but I wrote a simulation to approximate the result or verified at least the given example - usually I sketched a few ideas, too | |
black | problems are solved but access to the solution is blocked for a few days until the next problem is published | |
[new] | the flashing problem is the one I solved most recently |
I stopped working on Project Euler problems around the time they released 617.
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 |
151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 |
176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 |
201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 |
226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 |
251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 |
276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 |
301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 |
326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 |
351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 |
376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 |
401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 |
426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 |
451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 |
476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 |
501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 |
526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 |
551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 |
576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 |
601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 |
626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 |
651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 |
676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 |
701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 |
726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 |
751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 |
776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 |
801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 |
I scored 13526 points (out of 15700 possible points, top rank was 17 out of ≈60000 in August 2017) at Hackerrank's Project Euler+.
My username at Project Euler is stephanbrumme while it's stbrumme at Hackerrank.
Look at my progress and performance pages to get more details.
Copyright
I hope you enjoy my code and learn something - or give me feedback how I can improve my solutions.
All of my solutions can be used for any purpose and I am in no way liable for any damages caused.
You can even remove my name and claim it's yours. But then you shall burn in hell.
The problems and most of the problems' images were created by Project Euler.
Thanks for all their endless effort !!!
<< problem 278 - Linear Combinations of Semiprimes | Ant and seeds - problem 280 >> |