首先,Pascal的三角形看起来像这样:
您看到的第一行是第零行。
这没什么不寻常的 当你是一名计算机科学家。
帕斯卡三角形中的每个项都可以通过以下公式预测:
C(n,k)= n! / [k! *(n - k)!],其中" n"是行和" k"是从0到n的任何整数。
因此,可以用(n,k)组合预测Pascal的三角形:
这就是你在上图中看到的内容。
Pascal的三角形基本上是二项式概率:
(H + T)^ n#你翻转一个双面硬币" n"时间和它落在"头"或者"尾巴"并且你在一组系数中收集每个系数的频率,对于n = 3,我们得到扩展:
(H + T)^ 3 = 1(H ^ 3)+ 3(H ^ 2)(T)+ 3(H)(T ^ 2)+ 1(T ^ 3),其中那些系数: 1,3,3,1是帕斯卡三角形的第3行。
我定义了一个阶乘(!)和一个组合,并且能够获得 Pascal三角形的任何一行上的系数数字,带有一些循环Perl代码:
use strict;
use warnings;
# Note the first row is row 0.
print("\nWhich row of Pascal's triangle to display: ");
my $row = <STDIN>; # The row that you want to display # This is also n.
my $terms = $row + 1; # The number of terms is one more than the row number.
Pascal_Row($row); # Print the Pascal numbers for that row.
# Function displays the numbers for a row of Pascal's triangle.
#######################################################
sub Pascal_Row
{
my $row = shift; # Row is passed in.
for(my $k = 0; $k < $row + 1; $k++) # k alternates, but not the row which is n.
{
print(combination($row, $k), "\t") # Print each row.
}
print("\n"); # Print a newline after each time this function is called.
}
# This computes the factorial of a number.
###########################################
sub factorial
{
my $number = shift; # argument.
my $factorial_number = 1; # initalize the factorial.
for(my $i = 1; $i <= $number; $i++)
{
$factorial_number *= $i; # compute the factorial, by multiplying all terms up to and including number.
}
return $factorial_number; # Return the factorial number.
}
# Computes a matehmatical combination usually denoted as C(n, k)
# where n is the row number, and k is each item in a row of Pascal's traingle
sub combination
{
my($n, $k) = @_; # from input.
# This is the mathematical formula for a combination.
my $combination_number = factorial($n) / (factorial($k) * factorial($n - $k));
return $combination_number # And returning it.
}
如果我运行代码并询问Pascal三角形的第8行,我会得到这个:
Which row of Pascal's triangle to display: 8
1 8 28 56 70 56 28 8 1
对于帕斯卡三角形的第8行来说,这完全正确。如果我将它从第0行循环到Pascal三角形的第8行,我会得到所有正确的Pascal三角形行,但它看起来不像三角形(看起来会更像像一个盒子),所以我怎么能修改我的代码来调整缩进。
如果我想要显示8行Pascal三角形,如何确定缩进第一行的数量?如何制作一个三角形&#34;?
答案 0 :(得分:3)
左对齐三角形:
PaginableItem
居中三角形:
my $MAX_VAL_SIZE = 5;
for my $n (0...$N) {
my @row;
for my $k (0..$n) {
push @row, C($n, $k);
}
say join " ", map sprintf("%*d", $MAX_VAL_SIZE, $_), @row;
}
答案 1 :(得分:2)
这很棘手,因为数字的宽度变化对布局很重要。
每行需要缩进行中数字间隔的一半,适当地相乘(最后一行为零,第一行为-1) - 也就是说,如果数字本身的宽度相等。
但除了前几行之外,情况并非如此;数字占用不同的空间。一种方法是使用固定宽度的数字,并使用该宽度调整缩进和分离。
首先计算所有行,以便找到数字的最大宽度。
use warnings;
use strict;
use feature 'say';
use List::Util qw(max);
my $max_row = (shift || 8);
my @rows = map { pascal_row($_) } 0..$max_row-1;
my $max_num_wd = max map { length } @{$rows[-1]};
my $pad = 1; # choice (must be non-zero)
my $sep = ' ' x ($max_num_wd + 2*$pad);
my $lead_sp = ' ' x ($max_num_wd + $pad);
for my $n (0..$#rows) {
say $lead_sp x ($max_row-1-$n),
join $sep, map { sprintf "%${max_num_wd}d", $_ } @{$rows[$n]};
}
sub pascal_row {
my ($row) = @_;
return [ map { n_over_k($row, $_) } 0..$row ];
}
sub n_over_k {
my ($n, $k) = @_;
return factorial($n) / (factorial($k) * factorial($n - $k));
}
sub factorial {
my ($n) = @_;
my $fact = 1;
$fact *= $_ for 2..$n;
return $fact;
}
这将打印正确的布局。 $pad
是一个任意整数,用于超过最大数字宽度的额外空间,用于缩进和分离;它必须> 0才能协调它们。 (分离需要上面一行中心数左右两侧的空间,因此系数为2.)
原始代码,在计算时打印,因此$max_num_wd
提前设置
# (includes and subs same as above except for List::Util)
my $max_row = (shift || 8);
my $max_num_wd = 4; # maximum width of numbers
my $pad = 1; # choice (non-zero)
my $sep = ' ' x ($max_num_wd + 2*$pad);
my $lead_sp = ' ' x ($max_num_wd + $pad);
for my $n (0..$max_row-1) {
my @row = @{ pascal_row($n) };
say $lead_sp x ($max_row-1-$n),
join $sep, map { sprintf "%${max_num_wd}d", $_ } @row;
}
这将打印正确的布局,数字宽度最多为4位,或者需要调整$max_num_wd
。
答案 2 :(得分:2)
以下是另一种方法:
use strict;
use warnings;
sub fact {
my $n = shift;
return 1 if $n < 1;
return $n * fact($n - 1);
}
sub n_over_k {
my $n = shift;
my $k = shift;
return fact($n) / ( fact($k) * fact($n - $k) );
}
sub pascal_row {
my $n = shift;
return map { n_over_k($n - 1, $_) } (0 .. $n - 1);
}
my $n = shift || 8;
# $maxw is the first odd width where the biggest number will fit
my $max = 0;
map { $max = $_ if $_ > $max } pascal_row($n);
my $maxw = length('' . $max);
$maxw += ($maxw + 1) % 2;
# Print the Pascal´s triangle
foreach my $i (1..$n) {
print ' ' x ( ( $maxw + 1 ) * ($n - $i) / 2 );
foreach my $j ( pascal_row($i) ) {
printf "%${maxw}d ", $j;
}
print "\n";
}
怎么做?将每个数字设置在第一个奇数宽度内,其中要打印的数字的最大值将适合。这是因为数字用空格分隔,这将使每个宽度均匀(对于奇值三角形行,可以将其整除。)然后使用printf
格式化数字。例如,%5d
会将数字对齐在5个字符以内。使用' ' x N
生成一个N
个空格字符串,前面包含必要空格的除最后一行之外的每一行。
Pascal的三角形8:
# pascal.pl 8
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
Pascal的三角形13:
# pascal.pl 13
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
答案 3 :(得分:1)
您可以生成没有任何组合公式的三角形。
这样做的原因是这是最有效的方法。
基本思想是采用观察,即下一个值 row是上面2个元素的总和。
此解决方案也是如何使用数组的一个很好的示例 (参考)数组。
一个有趣的特征是缩进是从 最后一行中的中元素(具有最大值)。
为了提供三角形的漂亮外观,单元格大小必须是偶数。 &#34;基本&#34;缩进是这个大小的一半。 每行的实际缩进是这个基本大小,乘以相应的 number,从行索引和行总数派生。
整个脚本如下:
use strict;
use warnings;
use feature qw(say);
use POSIX qw(ceil);
my $rowCnt = 14; # How many rows
say "Pascal Triangle with $rowCnt rows:";
# Rows container, filled with a single row (containing single 1)
my @rows = ([ 1 ]);
my ($lastRow, $row, $ind);
# Generate / add further rows
for ($ind = 1; $ind < $rowCnt; $ind++) {
$lastRow = $rows[$#rows]; # Last row gathered so far
push(@rows, getNextRow($lastRow));
}
$lastRow = $rows[$#rows];
# Middle elem. of the last row
my $midElem = $$lastRow[($rowCnt - 1) / 2];
# No of digits + separator, rounded up to even
my $elemSize = ceil((length($midElem) + 1) / 2) * 2;
my $shf = $elemSize / 2; # Shift size for a sigle step
# Print rows
for ($ind = 0; $ind < $rowCnt; $ind++) {
my $row = $rows[$ind];
my $spc = $shf * ($rowCnt - $ind - 1);
printRow($spc, $row, $elemSize);
}
sub getNextRow { # Create the next row and return the reference to it
my $lastRow = $_[0]; # Read param
my @row = (1); # Start the new row from a single 1
for (my $i = 0; $i < $#$lastRow; $i++) {
push(@row, $$lastRow[$i] + $$lastRow[$i + 1]);
}
push(@row, 1); # Add terminating 1
return \@row; # Result - reference to the created row
}
sub printRow { # Print a row of the triangle
my ($leadSpc, $row, $elemSize) = @_; # Read params
# Leading spaces and the initial element (always 1)
printf("%s1", ' ' x $leadSpc);
# Print the rest of the row
for (my $i = 1; $i <= $#$row; $i++) {
printf("%*d", $elemSize, $$row[$i]);
}
print("\n");
}