Perl, 65 59 55 54 ไบต์
รวมถึง +2 สำหรับ -ap
ทำงานกับขนาดต้นไม้บน 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
คำอธิบาย
หากคุณเขียนต้นไม้ใหม่
3
|
2 4
\ /
1
|
0
ถึงหนึ่งที่แต่ละโหนดมีชุดของบรรพบุรุษทั้งหมดและตัวเอง:
{3}
|
{2,3} {4}
\ /
\ /
{1,2,3,4}
|
{0,1,2,3,4}
จากนั้นเราสามารถอธิบายเช่นโหนดทั้งหมดเส้นทางจาก 4 เป็น 3 เป็น:
- โหนดทั้งหมดที่มี 3 แต่ไม่ใช่ 4 (ลงจาก 3)
- โหนดทั้งหมดที่มี 4 แต่ไม่ 3 (ลงจาก 4)
- โหนดสูงสุดที่มีทั้ง 3 และ 4 (การรวม)
จำนวนของขอบคือหนึ่งน้อยกว่าจำนวนโหนดเพื่อให้เราสามารถใช้เพื่อละเว้นจุดเชื่อมต่อดังนั้นจำนวนของขอบบนเส้นทางจาก 4 ถึง 3 คือ 3 เพราะ:
- จำนวนโหนดที่มี 3 แต่ไม่ใช่โหนด 4: 2
- จำนวนโหนดที่มี 4 แต่ไม่ใช่โหนด 3: 1
โปรดสังเกตว่าวิธีนี้ใช้ได้กับพา ธ ที่ไปยังเป้าหมายโดยตรงเช่นสำหรับเส้นทางจาก 3 ถึง 2 จำนวนขอบคือ 1 เพราะ:
- จำนวนโหนดที่มี 2 แต่ไม่ใช่โหนด 3: 0
- จำนวนโหนดที่มี 3 แต่ไม่ใช่โหนด 2: 1
จากนั้นเราสามารถหาผลรวมของชุดค่าผสมเหล่านี้ทั้งหมด
หากคุณแทนที่จะมองไปที่เพียงโหนดเช่นโหนด 2 {2,3}
กับชุดบรรพบุรุษ โหนดนี้จะมีส่วนร่วมในครั้งเดียวเมื่อการประมวลผลเส้นทาง2 to 1
เพราะมันมี 2 แต่ไม่ได้เป็น 1 3 to 2
เนื่องจากมันมีทั้ง 2 และ 3 แต่มันจะมีส่วนร่วมเมื่อประมวลผลเส้นทาง4 to 3
ตั้งแต่มันมี 3 แต่ หมายเลข 4 โดยทั่วไปแล้วตัวเลขในชุดบรรพบุรุษของโหนดจะมีส่วนหนึ่งสำหรับแต่ละเพื่อนบ้าน (หนึ่งที่ต่ำกว่าสูงกว่า) ที่ไม่ได้อยู่ในชุด ยกเว้นองค์ประกอบสูงสุด (4 ในกรณีนี้) ซึ่งสนับสนุนเฉพาะเพื่อนบ้านต่ำ 3 เนื่องจากไม่มีเส้นทาง5 to 4
. Simular 0 เป็นด้านเดียว แต่เนื่องจาก 0 อยู่ที่รากของต้นไม้เสมอและมีตัวเลขทั้งหมด (เป็นการรวมขั้นสุดท้ายและเราไม่นับการรวม) ไม่มีการสนับสนุนใด ๆ จาก 0 ดังนั้นจึงง่ายที่สุดที่จะออกจากโหนด 0 ออกไปโดยสิ้นเชิง
ดังนั้นเราจึงสามารถแก้ปัญหาได้โดยดูที่บรรพบุรุษที่ตั้งค่าไว้สำหรับแต่ละโหนดนับการมีส่วนร่วมและผลรวมของโหนดทั้งหมด
เพื่อให้ง่ายต่อการประมวลผลเพื่อนบ้านฉันจะแสดงชุดบรรพบุรุษเป็นสตริงของช่องว่างและ 1 โดยที่แต่ละ 1 ที่ตำแหน่ง p แสดงว่า n-1-p เป็นบรรพบุรุษ เช่นในกรณีของเราn=5
ที่ 1 ที่ตำแหน่ง 0 หมายถึง 4 เป็นบรรพบุรุษ ฉันจะออกจากช่องว่างต่อท้าย ดังนั้นการเป็นตัวแทนที่แท้จริงของต้นไม้ฉันจะสร้างคือ:
" 1"
|
" 11" "1"
\ /
\ /
"1111"
โปรดสังเกตว่าฉันออกจากโหนด 0 ซึ่งจะถูกแทนด้วย"11111"
เพราะฉันจะไม่สนใจโหนด 0 (มันไม่เคยมีส่วนร่วม)
บรรพบุรุษที่ไม่มีเพื่อนบ้านต่ำกว่าจะถูกแทนด้วยการสิ้นสุดของลำดับที่ 1 บรรพบุรุษที่ไม่มีเพื่อนบ้านที่สูงกว่าจะถูกแทนด้วยการเริ่มต้นลำดับที่ 1 แต่เราควรเพิกเฉยต่อการเริ่มต้นลำดับที่จุดเริ่มต้นของสตริงเนื่องจากสิ่งนี้จะแสดงถึงเส้นทาง5 to 4
ที่ไม่มีอยู่ ชุดนี้จะถูกจับคู่ตรงโดย /.\b/
regex
การสร้างสตริงบรรพบุรุษทำโดยการประมวลผลโหนดทั้งหมดตามลำดับn-1 .. 1
และมีการตั้งค่า 1 ในตำแหน่งสำหรับโหนดตัวเองและการทำ "หรือ" ลงในลูกหลาน
ด้วยโปรแกรมที่ง่ายต่อการเข้าใจ:
-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
โปรดสังเกตว่าการแทนที่/.\b/
ด้วยการ/\b/
แก้ปัญหารุ่นไปกลับของปัญหานี้ที่ tarzan ใช้เส้นทางด้วย0 to n-1
ตัวอย่างบางส่วนของวิธีที่สตริงบรรพบุรุษดู (ตามลำดับ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