การสลับหมายเลข [ปิด]


10

นี่เป็นปริศนาทั่วไปที่หลายคนแก้ไขด้วยตนเอง ตอนนี้เป็นเวลาที่จะเขียนอัลกอริทึมเพื่อแก้ปัญหาเดียวกัน

มีไม้ขีดไฟจำนวนเท่ากันเรียงกันในสองด้านที่แตกต่างกันหันหน้าไปทางทิศทางของกันและกัน มีช่องว่างเดียวระหว่างพวกเขา พูดอะไรบางอย่างเช่นรูปต่อไปนี้ (ถ้าจำนวนไม้ขีดทั้งหมดเท่ากับ 4)

ป้อนคำอธิบายรูปภาพที่นี่

ไม้เท้าแต่ละอันสามารถเลื่อนไปข้างหน้าหนึ่งก้าวในทิศทางไปข้างหน้า (หากว่างด้านหน้าทันทีเป็นอิสระ) หรือสามารถกระโดดข้ามแท่งหนึ่งอันที่ด้านหน้าและลงสู่พื้นที่ว่าง (ถ้าพื้นที่ว่างว่าง) ไม่สามารถเคลื่อนที่ในทิศทางตรงกันข้าม (แม้พื้นที่ว่าง) ไม่อนุญาตให้ย้อนกลับได้ อนุญาตให้ย้ายได้เพียงหนึ่งครั้งในขั้นตอนเดียว

ตอนนี้คุณต้องเขียนอัลกอริทึมเพื่อค้นหาขั้นตอนต่ำสุดที่จำเป็นต้องใช้ซึ่งไม้ขีดการจับคู่ด้านซ้ายทั้งหมดจะลงจอดทางด้านขวามือ

ตัวอย่างเช่น: หากมีไม้ขีดทั้งหมด 2 คู่ (1 ในแต่ละด้าน) ขั้นตอนจะเป็น:

ป้อนคำอธิบายรูปภาพที่นี่

หมายเหตุ: ในภาพด้านบนแท่งด้านซ้ายถูกขยับก่อน วิธีแก้ปัญหาอื่นจะเกิดขึ้นเมื่อแท่งด้านขวาเคลื่อนที่ก่อน แต่สำหรับปัญหานี้คุณต้องแก้ปัญหาเพียงข้อเดียวเท่านั้นและนั่นก็คือสมมติว่าแท่งด้านซ้ายเคลื่อนที่ก่อน

รูปต่อไปนี้อธิบายการเคลื่อนไหวด้วย 4 ไม้ขีด (2 ในแต่ละด้าน):

ป้อนคำอธิบายรูปภาพที่นี่

หมายเหตุ: ในภาพด้านบนแท่งด้านซ้ายถูกขยับก่อน วิธีแก้ปัญหาอื่นจะเกิดขึ้นเมื่อแท่งด้านขวาเคลื่อนที่ก่อน แต่สำหรับปัญหานี้คุณต้องแก้ปัญหาเพียงข้อเดียวเท่านั้นและนั่นก็คือสมมติว่าแท่งด้านซ้ายเคลื่อนที่ก่อน

[การสันนิษฐาน: อินพุตสามารถเป็นเลขคู่ใดก็ได้ระหว่าง 02 ถึง 14 (เช่น 1 ถึง 7 การจับคู่แท่งในแต่ละด้าน) สำหรับอินพุตภายนอกช่วงนี้คุณไม่จำเป็นต้องทำการตรวจสอบใด ๆ และไม่จำเป็นต้องให้ข้อความแสดงข้อผิดพลาดใด ๆ หมายเหตุ: ในผลลัพธ์แต่ละขั้นตอนจะถูกคั่นด้วย '|' อักขระ (ไพพ์) โปรแกรมเมอร์ภาษาโคบอลควรสันนิษฐานว่า PIC 9 (2) เป็นขนาดอินพุต & อาจสันนิษฐานว่าเอาต์พุตเป็นความยาวสูงสุดคงที่ 450 ตัวอักษรโดยมีช่องว่างด้านขวา]


ตัวอย่างอินพุต:

02  

ตัวอย่างผลลัพธ์:

01To02|03To01|02To03|


ตัวอย่างอินพุต:

04  

ตัวอย่างผลลัพธ์:

02To03|04To02|05To04|03To05|01To03|02To01|04To02|03To04|


ตัวอย่างอินพุต:

06  

ตัวอย่างผลลัพธ์:

03To04|05To03|06To05|04To06|02To04|01To02|03To01|05To03|07To05|06To07|04To06|02To04|03To02|05To03|04To05|

หากคุณไม่สามารถรวมภาพโดยตรงคุณสามารถจัดหาลิงค์ให้คนอื่นแก้ไขได้หรือไม่?
Peter Taylor

2
ฉันทำรูปภาพอย่างรวดเร็ว หวังว่าพวกเขาจะสอดคล้องกับความตั้งใจของผู้เขียนต้นฉบับ
primo

3
เงื่อนไขสำหรับชัยชนะ?
Shmiddty

คำตอบ:


3

APL 129

รหัสด้านล่างจะนำหน้าจอเข้าและส่งออกไปยังหน้าจอในรูปแบบที่ระบุ:

n←n,n++\1↓z←(⌽z),((¯1*~2|n)×n⍴2),z←⌽∊(¯1*2|⍳n)ר1,((⍳(n←.5×⍎⍞)-1)⍴¨2),¨1⋄(∊(((¯2↑¨'0',¨⍕¨n),¨⊂'To'),¨(¯2↑¨'0',¨⍕¨n-z)),¨⊂'|')~' '

รหัสที่สามที่ดีคือการจัดรูปแบบผลลัพธ์ ตรรกะสมบูรณ์โดยการเกิดขึ้นของสัญลักษณ์ in ในรหัส

ด้านล่างนี้เป็นผลลัพธ์สำหรับการป้อนข้อมูลของ 08 เป็นการตรวจสอบ:

04To05|06To04|07To06|05To07|03To05|02To03|04To02|06To04|08To06|09To08|07To09|05To07|03To05|01To03|02To01|04To02|06To04|08To06|07To08|05To07|03To05|04To03|06To04|05To06|

1
ฉันมักจะรู้สึกว่า APL กำลังโกง>. <
Shmiddty

@ Shmiddty ฉันกลัวว่าภาษาใด ๆ ที่ใช้สัญลักษณ์อย่างหมดจดเช่น APL, J, GolfScript ฯลฯ จะชนะการแข่งขันกอล์ฟรหัสกับภาษาที่ใช้คำที่ละเอียดมากขึ้น)
เกรแฮม

3

Javascript 178 174 161

promptสำหรับnแล้วalertคำตอบ (ไม่มี0ช่องว่างภายใน)

ล่าสุด:

t=1+(m=prompt(s=i='')/2);for(z=Math.abs;i++<m*2;)for(j=m-z(m-i),s+=(t+=a=(m%2^z(m+.5-i)%2-.5)*-2+1)+'To'+(t-a)+'|';j--;)s+=(t+=a=i%2*4-2)+'To'+(t-a)+'|';alert(s)

2:

z=Math.abs;t=m=prompt(o=[])/2;t++;for(s=i='';i++<m*2;)for(j=m-z(m-i),o.push((z(m+.5-i)%2-.5)?-1:1);j--;)o.push(i%2?2:-2);o.map(function(a){s+=(t+=a)+'To'+(t-a)+'|'});alert(s)

1:

t=m=prompt(o=[])/2+1;for(s=i='';++i<m;)for(j=i,o.push(i%2?-1:1);j--;)o.push(i%2?2:-2);o.concat(o.slice().reverse().slice(m-1)).map(function(a){s+=(t+=a)+'To'+(t-a)+'|'});alert(s)

สิ่งนี้ใช้แนวคิดที่ว่ารูปแบบถูกทำมิเรอร์:

Key
R='Jump Right'
r='Shift Right'
L='Jump Left'
l='Shift Left'
m='Move'
j='Jump'

ดังนั้นn=2รูปแบบของการเคลื่อนไหวคือ:

rLr
mjm

ซึ่งเท่ากับ

+1 -2 +1

รูปแบบนี้ซ้ำเหมือนเดิม ( n=8)

rLlRRrLLLlRRRRlLLLrRRlLr
mjmjjmjjjmjjjjmjjjmjjmjm
+1 -2 -1 +2 +2 +1 -2 -2 -2 -1 +2 +2 +2 +2 -1 -2 -2 -2 +1 +2 +2 -1 -2 +1

เราสามารถสังเกตเห็นลวดลายบางอย่างได้ที่นี่:

  1. การเคลื่อนไหวสลับกันระหว่างซ้ายและขวา
  2. จำนวนการเคลื่อนไหวในทิศทางที่เฉพาะเจาะจงเพิ่มขึ้นจาก 1 ถึงn/2ซึ่งทำซ้ำ 3 ครั้งจากนั้นลดลงเป็น 1
  3. ชนิดของการเคลื่อนไหวสลับไปมาระหว่างการเลื่อนและการกระโดดจำนวนกะในแถวเป็นค่าคงที่1และจำนวนของการกระโดดตามลำดับเพิ่มขึ้นจาก 1 ถึงn/2จากนั้นลดลงเป็น 1
  4. การรวมตัวของการเคลื่อนไหวมีค่าเป็น 0 เสมอ (ไม่แน่ใจว่าเกี่ยวข้องหรือไม่)

n=14:

rLlRRrLLLlRRRRrLLLLLlRRRRRRrLLLLLLLrRRRRRRlLLLLLrRRRRlLLLrRRlLr
mjmjjmjjjmjjjjmjjjjjmjjjjjjmjjjjjjjmjjjjjjmjjjjjmjjjjmjjjmjjmjm

ตัวอย่างผลลัพธ์:

f(2):

1To2|3To1|2To3| 

f(8):

4To5|6To4|7To6|5To7|3To5|2To3|4To2|6To4|8To6|9To8|7To9|5To7|3To5|1To3|2To1|4To2|6To4|8To6|7To8|5To7|3To5|4To3|6To4|5To6|

f(40):

20To21|22To20|23To22|21To23|19To21|18To19|20To18|22To20|24To22|25To24|23To25|21To23|19To21|17To19|16To17|18To16|20To18|22To20|24To22|26To24|27To26|25To27|23To25|21To23|19To21|17To19|15To17|14To15|16To14|18To16|20To18|22To20|24To22|26To24|28To26|29To28|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|12To13|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|31To30|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|10To11|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|33To32|31To33|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|9To11|8To9|10To8|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|34To32|35To34|33To35|31To33|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|9To11|7To9|6To7|8To6|10To8|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|34To32|36To34|37To36|35To37|33To35|31To33|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|9To11|7To9|5To7|4To5|6To4|8To6|10To8|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|34To32|36To34|38To36|39To38|37To39|35To37|33To35|31To33|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|9To11|7To9|5To7|3To5|2To3|4To2|6To4|8To6|10To8|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|34To32|36To34|38To36|40To38|41To40|39To41|37To39|35To37|33To35|31To33|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|9To11|7To9|5To7|3To5|1To3|2To1|4To2|6To4|8To6|10To8|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|34To32|36To34|38To36|40To38|39To40|37To39|35To37|33To35|31To33|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|9To11|7To9|5To7|3To5|4To3|6To4|8To6|10To8|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|34To32|36To34|38To36|37To38|35To37|33To35|31To33|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|9To11|7To9|5To7|6To5|8To6|10To8|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|34To32|36To34|35To36|33To35|31To33|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|9To11|7To9|8To7|10To8|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|34To32|33To34|31To33|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|9To11|10To9|12To10|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|32To30|31To32|29To31|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|11To13|12To11|14To12|16To14|18To16|20To18|22To20|24To22|26To24|28To26|30To28|29To30|27To29|25To27|23To25|21To23|19To21|17To19|15To17|13To15|14To13|16To14|18To16|20To18|22To20|24To22|26To24|28To26|27To28|25To27|23To25|21To23|19To21|17To19|15To17|16To15|18To16|20To18|22To20|24To22|26To24|25To26|23To25|21To23|19To21|17To19|18To17|20To18|22To20|24To22|23To24|21To23|19To21|20To19|22To20|21To22|

ต่อไปนี้เป็นรหัสเทียมเพื่อสาธิตวิธีการ:

var mid=cursor=N/2,delta
cursor++                 // the cursor is where the empty space is.
for(i=0; i++<N;){
  delta = (mid%2^abs(mid+.5-i)%2-.5)*-2+1;  // 1 or -1
  print((cursor+delta) + 'To' + cursor + '|')
  cursor+=delta
  for(j=mid-abs(mid-i);j--;)
  {
    delta = i%2*4-2  // 2 or -2
    print((cursor+delta) + 'To' + cursor + '|')
    cursor+=delta
  }
}

2
คุณขวาว่ารูปแบบที่มีความชัดเจนมากขึ้นด้วยและl/L/r/R m/jฉันชอบความคิดในการแยกระยะทางที่ย้ายออกจากทิศทาง
Gordon Bailey

2

C - 216 213

วิธีการแก้ปัญหาของฉันขึ้นอยู่กับข้อเท็จจริงสองประการ:

  1. ฟิลด์ "เป็น" เป็นช่อง "จาก" ของการย้ายครั้งก่อน (เนื่องจากคุณสร้างช่องว่างในพื้นที่ที่คุณย้ายเสมอและคุณจะย้ายไปที่ช่องว่างเสมอ)

  2. มีรูปแบบปกติมากสำหรับระยะทางและทิศทางที่เคลื่อนที่ สำหรับกรณีทดสอบ 3 รายการแรก ได้แก่ :

    1 -2 1

    1 -2 -1 2 2 -1 -2 1

    1 -2 -1 2 2 1 -2 -2 -2 1 2 2 -1 -2 1

โดยพื้นฐานแล้วฉันเพิ่งเขียนโปรแกรมเพื่อสร้างและทำตามรูปแบบนั้นต่อไป ฉันค่อนข้างมั่นใจว่าต้องมีวิธีเรียกซ้ำที่สวยงามและสง่างามกว่านี้มากในการเขียน แต่ฉันยังไม่ได้คิดออก:

#include <stdio.h>

int main(int argc, const char *argv[])
{
   int upper_bound = atoi(argv[1]) / 2;
   int len;
   int from;
   int to = upper_bound + 1;
   int direction = 1;
   int i;

   for(len = 1; len <= upper_bound; ++len){
      for(i = len-1; i >=0; --i){
         from = to - direction*(1 + (i!=0));
         printf("%02dTo%02d|",from,to);
         to = from;
      }
      direction*=-1;
   }
   for(i=1; i < len; ++i){
      from = to - direction*2;
      printf("%02dTo%02d|",from,to);
      to = from;
   }
   direction*=-1;
   for(--len; len >= 0; --len){
      for(i = 0; i < len; ++i){
         from = to - direction*(1 + (i!=0));
         printf("%02dTo%02d|",from,to);
         to = from;
      }
      direction*=-1;
   }
   return 0;
}

และเล่นกอล์ฟ (แม้ว่านี่จะเป็นรหัสที่ท้าทายไม่ใช่กอล์ฟ):

#define B {F=T-D*(1+(i!=0));printf("%02dTo%02d|",F,T);T=F;}D*=-1;
L,F,T,D,i;main(int U,char**A){U=atoi(A[1])/2;T=U+1;D=1;for(L=1;L<=U;++L){for(i=L-1;i>=0;--i)B}for(i=1;i<L;++i)B for(--L;L>=0;--L){for(i=0;i<L;++i)B}}

#define B {F=T-D*(1+(i!=0));printf("%02dTo%02d|",F,T);T=F;}D*=-1;
L,F,T,D,i;main(int U){scanf("%d",&U);U/=2;T=U+1;D=1;for(L=1;L<=U;++L){for(i=L-1;i>=0;--i)B}for(i=1;i<L;++i)B for(--L;L>=0;--L){for(i=0;i<L;++i)B}}

เมื่อฉันใช้เวอร์ชั่นกอล์ฟของคุณฉันได้รับ segfault
artistoex

ขอโทษที่ฉันลืมที่จะพูดถึงว่าการป้อนข้อมูลจะได้รับเป็นอาร์กิวเมนต์บรรทัดคำสั่ง - ถ้าคุณเรียกใช้โดยไม่มีข้อโต้แย้งมันจะ segfault scanfแต่จริงๆแล้วตอนนี้ที่คุณพูดถึงมันผมไม่ทราบว่าทำไมผมคิดว่าอาร์กิวเมนต์บรรทัดคำสั่งจะสั้นกว่า ฉันกำลังอัปเดตคำตอบด้วยรุ่นที่ดีกว่า
Gordon Bailey

รูปแบบที่เป็นที่เห็นได้ชัดมากขึ้นเมื่อคุณใช้ L / R / L / R (ใหญ่เป็น "กระโดด"): N(2)=rLr, N(4)=rLlRRlLr, N(6)=rLlRRrLLLrRRlLrฯลฯ
Shmiddty

2

มาติกา

วิธีการนี้จะสร้างNestลำดับเอ็ดของขนาดและทิศทางของการเคลื่อนไหวที่จัดรูปแบบเป็น{fromPosition,toPosition}เริ่มต้นด้วยตำแหน่งnโดยnอ้างถึงจำนวนคู่ที่ตรงกัน จากนั้นก็Folds {n, n+1}ลำดับในการทำงานที่เริ่มต้นด้วยการย้าย

z@n_:=(p=1;h@t_:=Append[{Table[2 (-1)^t,{t}]},{(-1)^(t+1)}];
k=Join[Reverse@Drop[#,n],#]&[Flatten@Nest[Prepend[#,h[p++]]&,{},n]];
Fold[Append[#,{#[[-1,1]]-#2,#[[-1,1]]}]&,{{n,n+k[[1]]}},Rest@k])

z[1]

{{1, 2}, {3, 1}, {2, 3}}


z[4]

{{4, 5}, {6, 4}, {7, 6}, {5, 7}, {3, 5}, {2, 3}, {4, 2}, {6, 4}, { 8, 6}, {9, 8}, {7, 9}, {5, 7}, {3, 5}, {1, 3}, {2, 1}, {4, 2}, {6, 4}, {8, 6}, {7, 8}, {5, 7}, {3, 5}, {4, 3}, {6, 4}, {5, 6}}


z[7]

{{7, 8}, {9, 7}, {10, 9}, {8, 10}, {6, 8}, {5, 6}, {7, 5}, {9, 7}, { 11, 9}, {12, 11}, {10,12}, {8, 10}, {6, 8}, {4, 6}, {3, 4}, {5, 3}, {7, 5}, {9, 7}, {11, 9}, {13, 11}, {14, 13}, {12, 14}, {10, 12}, {8, 10}, {6, 8} , {4, 6}, {2, 4}, {1, 2}, {3, 1}, {5, 3}, {7, 5}, {9, 7}, {11, 9}, { 13, 11}, {15, 13}, {14, 15}, {12, 14}, {10, 12}, {8, 10}, {6, 8}, {4, 6}, {2, 4}, {3, 2}, {5, 3}, {7, 5}, {9, 7}, {11, 9}, {13, 11}, {12, 13}, {10, 12} , {8, 10}, {6, 8}, {4, 6}, {5, 4}, {7, 5}, {9, 7}, {11, 9}, {10, 11}, { 8, 10}, {6, 8}, {7, 6}, {9, 7}, {8, 9}}


การแสดงการแลกเปลี่ยน

r, bและoเป็นรูปภาพหรือการจับคู่สีแดงการจับคู่สีน้ำเงินและไม่มีการจับคู่ตามลำดับ

ไม้ขีด

ต่อไปนี้จัดรูปแบบเอาต์พุตจากzเพื่อแสดงการแลกเปลี่ยนกับการจับคู่

swaps[n_]:=FoldList[Grid[{Permute[#[[1,1]],Cycles[{#2}]],Range[2n+1]}]&,
Grid[{Join[Table[r,{n}],{o},Table[b,{n}]],Range[2n+1]}],z[n]]

swapMatches[n_]:=Grid[Partition[swaps[n],2,2,1,""],Dividers->All]

swapsสร้างรายการของสถานะโดยใช้คำสั่งคู่ของzเป็นคำสั่งเพื่อเปลี่ยนแปลงรายการเริ่มต้นและรายการที่ตามมา

swaps[1]

swaps1

swapMatches แสดงสถานะในกริด

swapMatches[2]

swaps2

swapMatches[3]

swaps3


0

Javascript 191

function f(N) {
    n=N>>=i=c=a='1';n++
    s=z='0'
    for(k=b='34';i<N;k=i%2?a+=z+z:b+='44',i++)c=k+c
    t=''
    i=N*(N+1)/2
    l=2*i+N
    for(;l;n+=(i>=1?r=c[i-1]:i<=-N?c[-i-N]:k[1])-2,t+=(s=n>9?'':z)+n+a+'|',--l,--i)a='To'+s+n
    return t
}

จำนวนตัวอักษรที่ใช้ grep =|tr -d \ |wc -c


1
สวัสดีและยินดีต้อนรับสู่ codegolf! ฉันคิดว่าคุณจะพบทางออกของคุณไม่ได้สร้างผลลัพธ์ที่ถูกต้องสำหรับกรณีทดสอบใด ๆ ( jsfiddle.net/SJwaU ) สำหรับการป้อนข้อมูล02ค่าที่ถูกต้อง |แต่มันหายไปต่อท้าย สำหรับอีกสองกรณีค่าจะถูกปิดและการจัดรูปแบบของ10ยังผิด ยังไม่แน่ใจเกี่ยวกับวิธีการนับตัวละครของคุณ ทำไมคุณจึงนับเฉพาะฟังก์ชั่นลบด้วยผลตอบแทน
Gordon Bailey

@ กอร์ดอนโอ๊ะโอดูเหมือนว่าฉันทำผิดพลาดในการเพิ่มประสิทธิภาพล่าสุดของฉัน ขอบคุณสำหรับการชี้ให้เห็น ฉันนับร่างกายเพียงเพราะบน REPL นั่นคือทั้งหมดที่คุณต้องการ ฉันใส่การตกแต่งฟังก์ชั่นเพื่อความสะดวกเท่านั้น
artistoex

คุณต้องนับพื้นที่ว่างที่เกี่ยวข้อง (เช่นบรรทัดใหม่) ไปยังผลรวมของคุณ
Shmiddty

@shmiddty คำนึงถึงการtr -d \ |wc -cขึ้นบรรทัดใหม่
artistoex
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.