Perl, 65 59 55 54 byte
Termasuk +2 untuk -ap
Jalankan dengan ukuran pohon di STDIN:
for i in `seq 24`; do echo -n "$i: "; vines.pl <<< $i; echo; done
vines.pl
:
#!/usr/bin/perl -ap
$_=map{${"-@F"%$_}|=$_=$$_|$"x$p++.1;/.\b/g}1-$_..-1
Penjelasan
Jika Anda menulis ulang pohon itu
3
|
2 4
\ /
1
|
0
ke satu tempat setiap node berisi himpunan semua leluhur dan dirinya sendiri:
{3}
|
{2,3} {4}
\ /
\ /
{1,2,3,4}
|
{0,1,2,3,4}
Kemudian kita bisa menggambarkan misalnya semua node path dari 4 ke 3 sebagai:
- Semua node yang berisi 3 tetapi tidak 4 (turun dari 3)
- Semua node yang berisi 4 tetapi tidak 3 (turun dari 4)
- Node tertinggi yang berisi 3 dan 4 (gabungan)
Jumlah tepi adalah satu kurang dari jumlah node sehingga kita dapat menggunakannya untuk mengabaikan titik bergabung, sehingga jumlah tepi pada jalur dari 4 ke 3 adalah 3 karena:
- Jumlah node yang berisi 3 tetapi tidak 4: 2 node
- Jumlah node yang berisi 4 tetapi tidak simpul 3: 1
Perhatikan bahwa ini juga berfungsi untuk jalur yang langsung turun ke targetnya, misalnya untuk jalur dari 3 ke 2 jumlah tepi adalah 1 karena:
- Jumlah node yang berisi 2 tetapi tidak 3: 0 node
- Jumlah node yang berisi 3 tetapi tidak 2: 1 node
Kami kemudian dapat menjumlahkan semua kombinasi ini.
Jika Anda melihat hanya sebuah simpul, misalnya simpul 2 dengan leluhur yang ditetapkan {2,3}
. Node ini akan berkontribusi sekali ketika memproses path 2 to 1
karena mengandung 2 tetapi tidak 1. Tidak akan memberikan kontribusi apa pun untuk path 3 to 2
karena memiliki 2 dan 3, tetapi akan berkontribusi sekali ketika memproses path 4 to 3
karena memiliki 3 tetapi no 4. Secara umum angka dalam set leluhur dari sebuah simpul akan berkontribusi satu untuk setiap tetangga (satu lebih rendah dari yang lebih tinggi) yang tidak ada dalam set. Kecuali untuk elemen maksimum (4 dalam hal ini) yang hanya berkontribusi untuk tetangga rendah 3 karena tidak ada jalan5 to 4
. Simular 0 adalah satu sisi, tetapi karena 0 selalu di akar pohon dan berisi semua angka (itu adalah gabungan akhir dan kami tidak menghitung bergabung) tidak pernah ada kontribusi dari 0 sehingga lebih mudah untuk meninggalkan simpul 0 sama sekali.
Jadi kita juga bisa menyelesaikan masalah dengan melihat set leluhur untuk setiap node, menghitung kontribusi dan menjumlahkan semua node.
Untuk dengan mudah memproses tetangga saya akan mewakili set leluhur sebagai string ruang dan 1 di mana masing-masing 1 pada posisi p menyatakan bahwa n-1-p adalah leluhur. Jadi misalnya dalam kasus kami n=5
1 pada posisi 0 menunjukkan 4 adalah leluhur. Saya akan meninggalkan ruang trailing. Jadi representasi sebenarnya dari pohon yang akan saya bangun adalah:
" 1"
|
" 11" "1"
\ /
\ /
"1111"
Perhatikan bahwa saya meninggalkan simpul 0 yang akan diwakili oleh "11111"
karena saya akan mengabaikan simpul 0 (tidak pernah berkontribusi).
Nenek moyang tanpa tetangga yang lebih rendah sekarang diwakili oleh akhir dari urutan 1. Nenek moyang tanpa tetangga yang lebih tinggi sekarang diwakili oleh permulaan urutan 1, tetapi kita harus mengabaikan permulaan urutan pada awal string karena ini akan mewakili jalur 5 to 4
yang tidak ada. Kombinasi ini sangat cocok dengan regex /.\b/
.
Membangun string leluhur dilakukan dengan memproses semua node dalam urutan n-1 .. 1
dan ada yang menetapkan 1 di posisi untuk node itu sendiri dan melakukan "atau" ke dalam keturunan.
Dengan semua itu, program ini cukup mudah dimengerti:
-ap read STDIN into $_ and @F
map{ }1-$_..-1 Process from n-1 to 1,
but use the negative
values so we can use a
perl sequence.
I will keep the current
ancestor for node $i in
global ${-$i} (another
reason to use negative
values since $1, $2 etc.
are read-only
$$_|$"x$p++.1 "Or" the current node
position into its ancestor
accumulator
$_= Assign the ancestor string
to $_. This will overwrite
the current counter value
but that has no influence
on the following counter
values
${"-@F"%$_}|= Merge the current node
ancestor string into the
successor
Notice that because this
is an |= the index
calculation was done
before the assignment
to $_ so $_ is still -i.
-n % -i = - (n % i), so
this is indeed the proper
index
/.\b/g As explained above this
gives the list of missing
higher and lower neighbours
but skips the start
$_= A map in scalar context
counts the number of
elements, so this assigns
the grand total to $_.
The -p implicitly prints
Perhatikan bahwa mengganti /.\b/
dengan /\b/
menyelesaikan versi bolak-balik dari masalah ini di mana tarzan juga mengambil jalannya0 to n-1
Beberapa contoh bagaimana string leluhur terlihat (diberikan secara berurutan n-1 .. 1
):
n=23:
1
1
1
1
1
1
1
1
1
1
1
11
1 1
1 1
1 1
11 11
1 1
11 1 1 11
1 1
1111 11 11 1111
111111111 111111111
1111111111111111111111
edges=68
n=24:
1
1
1
1
1
1
1
1
1
1
1
1
1 1
1 1
1 1
1 1
1 1
1 1 1 1
1 1
11 1 1 11
1 1 1 1
1 1 1 1
1 1
edges=82