如果一个数的所有真因子之和等于这个数,那么这个数被称为完全数。例如,28的所有真因子之和为1 + 2 + 4 + 7 + 14 = 28,所以28是一个完全数。
如果一个数的所有真因子之和小于这个数,称其为不足数,如果大于这个数,称其为过剩数。
纠结并不是因为这道题目有多么难,程序很快就写出来了,
分为两部,首先求出小于28123的过剩数。并把他们放在数组和哈希中,放在数组中是为了遍历,放在hash中是为了查找方便
其次,遍历1到28123,遍历数组,如果当前数减去数组里的一个数载哈希中存在,那么久pass。
这个程序的效率不高。有1分钟以上。
程序如下:
use strict; use warnings; my %hash; my $num; my $m; my @array; my $cout=0; for($num=12;$num<28123;$num++) { my $sum=1 ; for($m=2;$m<$num/2+1;$m++) { if(0==$num%$m && $m<$num/$m) { $sum=$sum+$m+$num/$m; } elsif(0==$num%$m && $m==$num/$m)#这个地方是一大败笔,没有考虑到相等的情况,在排除的时候对照百度的过剩数,发现少了196,才修改过来。 { $sum=$sum+$m; } else { next; } } if($sum>$num) { $cout=$cout+1; $hash{$num}=$num; $array[$cout]=$num; } } foreach(1..200) { print "$array[$_] "; } my $flag; my $result=0; my $i; my $j; for($i=1;$i<28123;$i++) { my $flag=0; foreach(1..$cout) { $j=$i-$array[$_]; if($j>10 && exists $hash{$j}) { $flag=1; last; } } if($flag==1) { next; } else { $result=$result+$i; last if($result>4179870) } } print "$result\n";
C:\WINDOWS\system32\cmd.exe /c perl "C:\Documents and Settings\Administrator\桌 面\names.pl" 12 18 20 24 30 36 40 42 48 54 56 60 66 70 72 78 80 84 88 90 96 100 102 104 108 1 12 114 120 126 132 138 140 144 150 156 160 162 168 174 176 180 186 192 196 198 2 00 204 208 210 216 220 222 224 228 234 240 246 252 258 260 264 270 272 276 280 2 82 288 294 300 304 306 308 312 318 320 324 330 336 340 342 348 350 352 354 360 3 64 366 368 372 378 380 384 390 392 396 400 402 408 414 416 420 426 432 438 440 4 44 448 450 456 460 462 464 468 474 476 480 486 490 492 498 500 504 510 516 520 5 22 528 532 534 540 544 546 550 552 558 560 564 570 572 576 580 582 588 594 600 6 06 608 612 616 618 620 624 630 636 640 642 644 648 650 654 660 666 672 678 680 6 84 690 696 700 702 704 708 714 720 726 728 732 736 738 740 744 748 750 756 760 7 62 768 770 774 780 784 786 792 798 800 804 810 812 816 820 4179871 Hit any key to close this window...结果是4179871
用了173s。还要继续优化。
优化的地方在于遍历着过剩数的时候,上面用了$num/2+1
优化后改成了$num**0.5+1;
程序如下:
use strict; use warnings; my $start_time=time; my %hash; my $num; my $m; my @array; my $cout=0; for($num=12;$num<28123;$num++) { my $sum=1 ; for($m=2;$m<$num**0.5+1;$m++) { if(0==$num%$m && $m<$num/$m) { $sum=$sum+$m+$num/$m; } elsif(0==$num%$m && $m==$num/$m) { $sum=$sum+$m; } else { next; } } if($sum>$num) { $cout=$cout+1; $hash{$num}=$num; $array[$cout]=$num; } } foreach(1..200) { print "$array[$_] "; } my $flag; my $result=0; my $i; my $j; for($i=1;$i<28123;$i++) { my $flag=0; foreach(1..$cout) { $j=$i-$array[$_]; if($j>10 && exists $hash{$j}) { $flag=1; last; } } if($flag==1) { next; } else { $result=$result+$i; last if($result>4179870) } } print "$result\n"; my $long=time-$start_time; print "$long\n";结果如下:
C:\WINDOWS\system32\cmd.exe /c perl "C:\Documents and Settings\Administrator\桌 面\names.pl" 12 18 20 24 30 36 40 42 48 54 56 60 66 70 72 78 80 84 88 90 96 100 102 104 108 1 12 114 120 126 132 138 140 144 150 156 160 162 168 174 176 180 186 192 196 198 2 00 204 208 210 216 220 222 224 228 234 240 246 252 258 260 264 270 272 276 280 2 82 288 294 300 304 306 308 312 318 320 324 330 336 340 342 348 350 352 354 360 3 64 366 368 372 378 380 384 390 392 396 400 402 408 414 416 420 426 432 438 440 4 44 448 450 456 460 462 464 468 474 476 480 486 490 492 498 500 504 510 516 520 5 22 528 532 534 540 544 546 550 552 558 560 564 570 572 576 580 582 588 594 600 6 06 608 612 616 618 620 624 630 636 640 642 644 648 650 654 660 666 672 678 680 6 84 690 696 700 702 704 708 714 720 726 728 732 736 738 740 744 748 750 756 760 7 62 768 770 774 780 784 786 792 798 800 804 810 812 816 820 4179871 7 Hit any key to close this window...
又进行了一点优化:再找最后的结果的时候,刚开始时把所有的过剩数都循环,
这里改成循环一半;
程序如下:
use strict; use warnings; my $start_time=time; my %hash; my $num; my $m; my @array; my $cout=0; for($num=12;$num<28123;$num++) { my $sum=1 ; for($m=2;$m<$num**0.5+1;$m++) { if(0==$num%$m && $m<$num/$m) { $sum=$sum+$m+$num/$m; } elsif(0==$num%$m && $m==$num/$m) { $sum=$sum+$m; } else { next; } } if($sum>$num) { $cout=$cout+1; $hash{$num}=$num; $array[$cout]=$num; } } my $flag; my $result=0; my $i; my $j; for($i=1;$i<28123;$i++) { my $flag=0; if($i<2*$cout) { foreach(1..$i/2+1) { $j=$i-$array[$_]; if($j>10 && exists $hash{$j}) { $flag=1; last; } } } else { foreach(1..$cout) { $j=$i-$array[$_]; if($j>10 && exists $hash{$j}) { $flag=1; last; } } } if($flag==1) { next; } else { $result=$result+$i; last if($result>4179870) } } print "$result\n"; my $long=time-$start_time; print "$long\n";
C:\WINDOWS\system32\cmd.exe /c perl "C:\Documents and Settings\A 面\names.pl" 4179871 5 Hit any key to close this window...