Perl, 65 59 55 54 Bytes
Beinhaltet +2 für -ap
Laufen Sie mit der Baumgröße auf 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
Erläuterung
Wenn Sie den Baum umschreiben
3
|
2 4
\ /
1
|
0
zu einem, wo jeder Knoten die Menge aller seiner Vorfahren und sich selbst enthält:
{3}
|
{2,3} {4}
\ /
\ /
{1,2,3,4}
|
{0,1,2,3,4}
Dann können wir zB für alle Knoten den Pfad von 4 nach 3 wie folgt beschreiben:
- Alle Knoten, die 3 aber nicht 4 enthalten (von 3 nach unten)
- Alle Knoten, die 4, aber nicht 3 enthalten (von 4 nach unten)
- Der höchste Knoten, der sowohl 3 als auch 4 enthält (der Join)
Die Anzahl der Kanten ist um eins niedriger als die Anzahl der Knoten, sodass der Verbindungspunkt ignoriert werden kann. Daher beträgt die Anzahl der Kanten auf dem Pfad von 4 bis 3 3, da:
- Die Anzahl der Knoten, die 3, aber nicht 4 enthalten: 2 Knoten
- Die Anzahl der Knoten, die 4, aber keinen 3: 1-Knoten enthalten
Beachten Sie, dass dies auch für einen Pfad funktioniert, der direkt zum Ziel führt, z. B. für den Pfad von 3 bis 2 ist die Anzahl der Kanten 1, weil:
- Die Anzahl der Knoten, die 2, aber keine 3: 0 Knoten enthalten
- Die Anzahl der Knoten, die 3, aber keinen 2: 1-Knoten enthalten
Wir können dann alle diese Kombinationen aufsummieren.
Betrachten Sie stattdessen nur einen Knoten, z. B. Knoten 2 mit gesetztem Vorfahren {2,3}
. Dieser Knoten wird bei der Verarbeitung des Pfads einmal beitragen, 2 to 1
da er eine 2, aber keine 1 enthält. Er wird nichts für den Pfad beitragen, 3 to 2
da er sowohl 2 als auch 3 hat. Er wird jedoch bei der Verarbeitung des Pfads einmal beitragen, 4 to 3
da er aber 3 hat nein 4. Im Allgemeinen trägt eine Zahl in der Vorfahrmenge eines Knotens eine Zahl für jeden Nachbarn bei (eine niedrigere oder eine höhere), die nicht in der Menge enthalten ist. Mit Ausnahme des maximalen Elements (in diesem Fall 4), das nur für den unteren Nachbarn 3 beiträgt, da kein Pfad vorhanden ist5 to 4
. Gleichzeitige 0 ist einseitig, aber da sich 0 immer an der Wurzel des Baums befindet und alle Zahlen enthält (es ist die ultimative Verknüpfung und wir zählen keine Verknüpfungen), gibt es keinen Beitrag von 0, so dass es am einfachsten ist, den Knoten 0 zu verlassen insgesamt aus.
Wir können das Problem also auch lösen, indem wir uns den Vorfahrensatz für jeden Knoten ansehen, die Beiträge zählen und über alle Knoten summieren.
Um Nachbarn einfach zu verarbeiten, werde ich die Vorfahrensätze als eine Folge von Leerzeichen und Einsen darstellen, wobei jede 1 an Position p darstellt, dass n-1-p ein Vorfahr ist. So bedeutet zB in unserem Fall n=5
einer 1 an Position 0, dass 4 ein Vorfahr ist. Ich werde Leerzeichen weglassen. Die tatsächliche Darstellung des Baums, den ich erstellen werde, lautet also:
" 1"
|
" 11" "1"
\ /
\ /
"1111"
Beachten Sie, dass ich den Knoten 0 ausgelassen habe, der durch dargestellt wird, "11111"
weil ich den Knoten 0 ignorieren werde (er trägt nie dazu bei).
Vorfahren ohne niedrigeren Nachbarn werden jetzt durch das Ende einer Folge von Einsen dargestellt. Vorfahren ohne höheren Nachbarn werden jetzt durch den Beginn einer Folge von Einsen dargestellt. Wir sollten jedoch jeden Beginn einer Folge am Anfang einer Zeichenfolge ignorieren, da dies den 5 to 4
nicht vorhandenen Pfad darstellen würde . Diese Kombination ist genau auf den regulären Ausdruck abgestimmt /.\b/
.
Das Erstellen der Vorfahrenzeichenfolgen erfolgt durch Verarbeiten aller Knoten in der Reihenfolge n-1 .. 1
und Setzen einer 1 an der Position für den Knoten selbst und Ausführen eines "oder" in den Nachkommen.
Trotzdem ist das Programm leicht zu verstehen:
-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
Beachten Sie, dass durch Ersetzen /.\b/
von /\b/
die Roundtrip-Version dieses Problems behoben wird, bei der auch Tarzan den Pfad nimmt0 to n-1
Einige Beispiele, wie die Vorfahrzeichenfolgen aussehen (in der angegebenen Reihenfolge 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