You are missing the keyword keys before %top_words as it has already been pointed out. Also as suggested by using an explicit reverse rather than swapping $a and $b you make your intentions clearer.
Rather than using the loop, you can just use an array slice as shown in the sample code below:
use warnings;
use strict;
use Smart::Comments;
my %words = (A => 440, B => 765, C => 369, D => 788,
E => 647, F => 216, G => 788,
H => 871, I => 733, J => 947,
K => 471, L => 875, M => 982,
N => 314, O => 564, P => 178,
Q => 212, R => 487, S => 768,
T => 939, U => 410, V => 753,
W => 765, X => 413, Y => 201,
Z => 233, AA => 553, AB => 601,
AC => 267, AD => 988, AE => 140,
AF => 784, AG => 667, AH => 987,
AI => 460, AJ => 186, AK => 592,
AL => 835, AM => 427, AN => 28,
AO => 214, AP => 912, AQ => 167,
AR => 421, AS => 400, AT => 583,
AU => 250, AV => 248, AW => 377,
AX => 850, AY => 862, AZ => 430,
AAA => 269, AAB => 656, AAC => 30,
AAD => 124, AAE => 444, AAF => 598,
AAG => 915, AAH => 276, AAI => 9,
AAJ => 831, AAK => 522, AAL => 753,
AAM => 799, AAN => 777, AAO => 330);
my @top_words = (reverse sort
{ $words{$a} <=> $words{$b} }
keys %words) [0 .. 19 ]; # Not [1 .. 20]!!!
### @top_words
|