ปัญหาการเดินทางฟักทอง


23

พื้นหลัง:

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

งาน:

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

การป้อนข้อมูล:

อายุการใช้งานของแท่งเทียนและรายการที่ตั้งหมู่บ้านในระบบพิกัดคาร์ทีเซียน แจ็คแพทช์ฟักทองมีต้นกำเนิดจากจะอยู่ที่ 0,0 คุณสามารถจัดรูปแบบอินพุตได้ตามที่คุณต้องการ เพื่อให้การเคลื่อนไหวของแจ็คง่ายขึ้นเขาสามารถเคลื่อนที่ในแนวนอนแนวตั้งหรือแนวทแยงมุมซึ่งหมายความว่าเทียนของเขาจะสูญเสีย 1 หรือ 1.5 (เขาใช้แนวทแยงมุมอีกต่อไป) หน่วยชีวิตทุกการเคลื่อนไหว เทียนไหม้เมื่ออายุการใช้งานน้อยกว่าหรือเท่ากับ 0

เอาท์พุท:

จำนวนเต็มเท่ากับจำนวนหมู่บ้านสูงสุดที่แจ็คสามารถเยี่ยมชมได้ก่อนที่เทียนจะไหม้

กฎ:

นี่คือดังนั้นรหัสที่สั้นที่สุดในหน่วยไบต์ชนะ ไม่อนุญาตช่องโหว่มาตรฐาน

กรณีทดสอบ:

// Format [lifespan] [list of village coordinates] -> [maximum visit-able villages]

4 -1,0 1,0 2,0 3,0 4,0 5,0 -> 3
4 1,1 2,2 3,3 -> 2
5 1,1 2,1 3,1 4,1 5,0 5,1 -> 4

9
หัวเราะคิกคักที่ชื่อ
หลุยส์เมนโด

3
"เพื่อให้การเคลื่อนไหวของแจ็คง่ายขึ้น" เป็นเรื่องที่น่าขันมากนี่เป็นเรื่องยากมากตอนนี้: D
PurkkaKoodari

1
ฉันคิดว่าผลลัพธ์เคสแรกของคุณควรเป็น 3 ถ้าฉันไม่ผิด
Numberknot

1
@ หมายเลขไม่เมื่อหมู่บ้านถูกทำให้กลัวพวกเขาจะไม่ตกหลุมรักเดียวกันเขาจะทำให้แต่ละหมู่บ้านกลัวได้เพียงครั้งเดียวเท่านั้น
Yodle

5
นี่เป็นปัญหาของ N-Pumpkin Hard ดังนั้นโดยทั่วไปจำนวนหมู่บ้านสูงสุดอาจหาได้ยาก มีหมู่บ้านจำนวนมากที่สุด?
edc65

คำตอบ:


9

เยลลี่, 30 29 27 25 ไบต์

_AṢæ..
0,0ṭṚç2\+\<S
Œ!ç€Ṁ

ลองออนไลน์!

เห็นได้ชัดว่าผลิตภัณฑ์ดอทลี่ของเยลลี่ไม่สนใจขนาดรายการที่ไม่ตรงกันและไม่ได้เพิ่มองค์ประกอบพิเศษของอาร์เรย์อื่นเพียงแค่เพิ่มเข้าไป ตัดออก 2 ไบต์

คำอธิบาย

_AṢæ..              Helper link to calculate distance. Arguments: a, b
_                     subtract the vertices from each other
 A                    take absolute values of axes
  Ṣ                   sort the axes
   æ..                dot product with [0.5]

0,0ṭṚç2\+\<S        Helper link to calculate max cities. Arguments: perm, max
0,0                   create pair [0,0]
   ṭ                  append that to the permutation
    Ṛ                 reverse the permutation (gets the [0,0] to the beginning)
     ç2\              find distances of each pair using the previous link
        +\            find all partial sums
          <           see if each sum was less than the max
           S          sum to count cases where it was

Œ!ç€Ṁ               Main link. Arguments: cities, max
Œ!                    get permutations of cities
  ç€                  find max cities for each permutation using the previous link
    Ṁ                 take the maximum

ในความคิดเห็น OP ขอให้จัดการได้มากถึง 1,000 หมู่บ้าน แต่คำตอบใด ๆ ที่สร้างและจัดเก็บการเปลี่ยนแปลงทั้งหมดจะล้มเหลวแม้แต่ 15 หมู่บ้าน (ประมาณ 1,300 ล้านการเปลี่ยนลำดับ)
edc65

@ edc65 ไม่มีที่ไหนพูดได้ว่าในกรณีที่จำเป็นต้องมีการทดสอบขนาดใหญ่ตราบใดที่อัลกอริทึมใช้งานได้ตามทฤษฎีจะมีเวลาและหน่วยความจำเพียงพอ (โปรแกรมที่สามารถแก้ปัญหา TSP สำหรับ n n 1,000 นั้นซับซ้อนดังนั้นพวกเขาจะไม่สนุกกับการเล่นกอล์ฟอีกต่อไป)
PurkkaKoodari

ตกลงไม่ 1,000 แต่ไม่ใช่ 15?
edc65

@ edc65 ฉันไม่สามารถหาอัลกอริธึมที่จะเร็วและใช้งานได้ง่ายใน Jelly ฉันอาจมองหาวิธีการแก้ปัญหาที่มีประสิทธิภาพมากขึ้น (เช่น Held-Karp) ในภาษาอื่น BTW ไม่มีคำตอบใดที่ใช้อัลกอริธึมที่รวดเร็วจริงๆ JS หนึ่งดีกว่า แต่ช้าถ้ามีหลายเมืองในระยะ
PurkkaKoodari

5

Java 7 206 201 ไบต์

ขอบคุณ @KevinCruijssen สำหรับการบันทึก 5 ไบต์

int f(float e,int[]a,int[]b){int x=0,y=0,c=0,d=0,t;float s;for(int i:a){s=(i!=x&b[c]==y)|(i==x&b[c]!=y)?Math.sqrt((t=i-x)*t+(t=b[c]-y)*t)*1:Math.abs(i-x)*1.5;d+=e-s>=0?1:0;e-=s;x=i;y=b[c++];}return d;}

Ungolfed

class Travellingpumpkin {

public static void main(String[] args) {

    System.out.println(f( 5 ,new int[] { 1,2,3,4,5,5 } , new int[] { 1,1,1,1,0,1 } ));

}
static int f( double e , int[]a , int[]b ) {
    int x = 0 , y = 0 , c = 0 , d = 0 , t;
    double s ;

    for ( int i : a ) {
    s = ( i != x & b[c] == y )|( i == x & b[c] != y )
         ? Math.sqrt( ( t = i - x ) * t + ( t = b[c] - y ) * t ) * 1
         : Math.abs( i - x ) * 1.5 ;


        d += e-s >= 0 ? 1 : 0 ;
        e -= s ;
        x = i ; y = b [ c++ ] ;
    }
    return d ;

}

   }

2
ดีรวมไปถึงแบบฟอร์ม "ungolfed" แม้ว่าคุณจะเปิดมันในฉันคิดว่าผู้ตรวจสอบรหัสจะไม่เรียกว่า ungolfed ;)
Wildcard

+1 สิ่งหนึ่งที่กอล์ฟ: คุณใช้i-xสองครั้งและb[c]-yครั้งที่สองเพื่อให้คุณสามารถเพิ่ม,tการ ints แล้วใช้นี้แทนMath.sqrt((t=i-x)*t+(t=b[c]-y)*t)*1 Math.sqrt((i-x)*(i-x)+(b[c]-y)*(b[c]-y))*1
Kevin Cruijssen

สิ่งนี้สามารถใช้งานได้อย่างไรในกรณีทั่วไป
edc65

3

สกาลา, 196 ไบต์

def f(l:Int,c:(Int,Int)*)=c.permutations.map(x=>((0,0)+:x sliding 2 map{p=>val Seq(c,d)=Seq((p(0)._1-p(1)._1)abs,(p(0)._2-p(1)._2)abs).sorted
c*1.5+(d-c)}scanLeft 0d)(_+_)takeWhile(_<l)size).max-1

Ungolfed:

def g (l: Int, c: (Int, Int)*) = {
    c.permutations
    .map { x =>
        ((0, 0) +: x).sliding(2).map({ p =>
            val Seq(c, d) = Seq((p(0)._1 - p(1)._1) abs, (p(0)._2 - p(1)._2) abs).sorted
            c * 1.5 + (d - c)
        }).scanLeft(0d)(_ + _).takeWhile(_ < l).size
    }.max - 1
}

Explanantion:

def f(l:Int,c:(Int,Int)*)= //defien a function with an int and a vararg-int-pait parameter
  c.permutations           //get the permutations of c, that is all possible routes
  .map(x=>                 //map each of them to...
    ((0,0)+:x                //prepend (0,0)
    sliding 2                //convert to a sequence of consecutive elemtens
    map{p=>                  //and map each of them to their distance:
      val Seq(c,d)=Seq(        //create a sequence of
        (p(0)._1-p(1)._1)abs,  //of the absolute distance between the x points
        (p(0)._2-p(1)._2)abs   //and he absolute distance between the y coordinates
      ).sorted                 //sort them and assign the smaller one to c and the larger one to d
      c*1.5+(d-c)              //we do the minimum difference diagonally
    }                        //we now have a sequence of sequence of the distances for each route
    scanLeft 0d)(_+_)       //calculate the cumulative sum
    takeWhile(_<l)          //and drop all elements that are larger than the candle lifespan
    size                    //take the size
  ).max-1                   //take the maximum, taht is the size of the largest route and subtract 1 because we added (0,0) at the beginning

3

JavaScript (ES6), 145

ฟังก์ชันเรียกซ้ำแบบไม่ระบุชื่อพารามิเตอร์sคืออายุการใช้งานของเทียนพารามิเตอร์lคือรายการพิกัดหมู่บ้าน

การค้นหาความลึกครั้งแรกหยุดเมื่อระยะทางถึงอายุการใช้งานของเทียน

f=(s,l,x=0,y=0,v=0,A=Math.abs,X=Math.max)=>X(v,...l.map(([t,u],i,[h,...l],q=A(t-x),p=A(u-y),d=(l[i-1]=h,p+q+X(p,q))/2)=>s<=d?v:f(s-d,l,t,u,1+v)))

golfed น้อยดูตัวอย่างด้านล่าง

ทดสอบ

f=(s,l,x=0,y=0,v=0,A=Math.abs,X=Math.max)=>
  X(v,...l.map(
      ([t,u],i,[h,...l],q=A(t-x),p=A(u-y),d=(l[i-1]=h,p+q+X(p,q))/2)=>
      s<=d?v:f(s-d,l,t,u,1+v)
  ))

// ungolfed version

F=(s, l, 
   x=0, y=0, // current position
   v=0 // current number of visited sites 
  ) =>
   Math.max(v, ...l.map(
     (
       [t,u], i, [h,...l], // lambda arguments
       q = Math.abs(t-x), p = Math.abs(u-y), // locals
       d = (p+q+Math.max(p,q))/2
     ) => (
       l[i-1] = h,
       s <= d 
         ? v 
         : F(s-d, l, t, u, v+1)
     ) 
  ))

;[[4,[[-1,0],[1,0],[2,0],[3,0],[4,0],[5,0]], 3]
,[4, [[1,1],[2,2],[3,3]], 2]
,[5, [[1,1],[2,1],[3,1],[4,1],[5,0],[5,1]], 4]
].forEach(test=>{
  var span=test[0],list=test[1],check=test[2],
      result = f(span, list)
  console.log(result==check?'OK':'KO',span, list+'', result)
})


3

MATL , 27 ไบต์

EH:"iY@OwYc!d|]yyXl++Ys>sX>

แก้ไข (26 พฤศจิกายน 2016): เนื่องจากมีการเปลี่ยนแปลงในการทำงานก็จะต้องมีการเปลี่ยนรหัสข้างต้นโดยXl 2$X>ลิงก์ด้านล่างรวมการแก้ไขดังกล่าว

ลองออนไลน์! หรือตรวจสอบกรณีทดสอบทั้งหมด

คำอธิบาย

ระยะฟักทองระหว่างเมืองทั้งสองแยกออกจากกันΔ xและΔ Yในแต่ละพิกัดที่สามารถรับได้เป็น (| Δ x | + | Δ Y | + max (| Δ x |, | Δ Y |)) / 2

รหัสดังต่อไปนี้ขั้นตอน:

  1. สร้างการเรียงสับเปลี่ยนทั้งหมดของพิกัดxและพิกัดyและเติม a เป็น 0 แต่ละอันการเปลี่ยนรูปแต่ละครั้งแทนเส้นทางที่เป็นไปได้
  2. คำนวณความแตกต่างติดต่อกันแบบสัมบูรณ์สำหรับแต่ละเส้นทาง (เหล่านี้คือ | Δ x | และ | Δ y | ด้านบน)
  3. รับระยะทางฟักทองสำหรับแต่ละขั้นตอนของแต่ละเส้นทาง
  4. คำนวณผลรวมระยะทางสะสมสำหรับแต่ละเส้นทาง
  5. ค้นหาสำหรับแต่ละเส้นทางจำนวนของขั้นตอนก่อนที่ระยะทางสะสมจะถึงอายุของ chandle
  6. ใช้เวลาสูงสุดข้างต้น

รหัสความคิดเห็น:

E        % Input candle lifespan implicitly. Multiply by 2
H:"      % Do thie twice
  i      %   Input array of x or y coordinates
  Y@     %   All permutations. Gives a matrix, with each permutation in a row
  OwYc   %   Prepend a 0 to each row
  !      %   Transpose
  d|     %   Consecutive differences along each column. Absolute value
]        % End
yy       % Duplicate the two matrices (x and y coordinates of all paths)
Xl       % Take maximum between the two, element-wise
++       % Add twice. This gives twice the pumpkin distance
Ys       % Cumulative sum along each column
>        % True for cumulative sums that exceed twice the candle lifespan
s        % Sum of true values for each column
X>       % Maximum of the resulting row array. Inmplicitly display

MATL สามารถสร้างการเรียงสับเปลี่ยนทั้งหมด 1,000 คู่ (x, y) ได้หรือไม่
edc65

@ edc65 ไม่นั่นมันมากเกินไป (มีการเปลี่ยนแปลงมากกว่า 10 ^ 2500 องค์ประกอบ 1,000 รายการ) ฉันไม่คิดว่าภาษาใดจะทำได้
Luis Mendo

ในความคิดเห็น OP ขอให้จัดการได้มากถึง 1,000 หมู่บ้าน แต่คำตอบใด ๆ ที่สร้างและจัดเก็บการเปลี่ยนแปลงทั้งหมดจะล้มเหลวแม้แต่ 15 หมู่บ้าน (ประมาณ 1,300 ล้านการเปลี่ยนลำดับ)
edc65

@ edc65 อ่าฉันเข้าใจแล้ว มี 1,000 หมู่บ้านที่ดูเหมือนไม่สมจริงหากปัญหานั้นเกิดจากปัญหา NP-hard อย่างที่เห็น
Luis Mendo

2

Python 2.7 , 422 ไบต์

ขอบคุณ NoOneIsHere สำหรับการชี้ให้เห็นการปรับปรุงเพิ่มเติม!

ขอบคุณ edc65 สำหรับการไม่บันทึกรายการ แต่ใช้ตัววนซ้ำแทน!

ลองออนไลน์!

from itertools import permutations
def d(s,e):
    d=0
    while s!=e:
        x=1 if s[0]<e[0] else -1 if s[0]>e[0] else 0
        y=1 if s[1]<e[1] else -1 if s[1]>e[1] else 0
        s=(s[0]+x,s[1]+y)
        d+=(1,1.5)[x and y]
return d
l,m=4,0
for o in permutations([(1,1),(2,2),(3,3)]):
    a,c=l-d((0,0),o[0]),1
    for j in range(len(o)-1):
        a-=d(o[j],o[j+1])
        c+=(0,1)[a>0]
    m=max(c,m)
print m

คำอธิบาย:

ฟังก์ชั่นคำนวณระยะห่างระหว่างสองจุดตามกฎที่กำหนดวงวนซ้ำผ่านการเรียงสับเปลี่ยนทั้งหมดที่สร้างโดยเครื่องกำเนิดของอินพุตและคำนวณระยะทางถ้าระยะทางน้อยกว่าอายุการใช้งานของเทียนมันจะลบออกและเพิ่มสถานที่ลงใน ตัวนับหากตัวนับนั้นมากกว่า max สูงสุดในปัจจุบันมันจะแทนที่มัน

ungolfed:

from itertools import permutations

def distance(start_pos, end_pos):
    distance = 0
    while start_pos != end_pos:
        mod_x = 1 if start_pos[0] < end_pos[0] else -1 if start_pos[0] > end_pos[0] else 0
        mod_y = 1 if start_pos[1] < end_pos[1] else -1 if start_pos[1] > end_pos[1] else 0
        start_pos = (start_pos[0] + mod_x, start_pos[1] + mod_y)
        distance += (1, 1.5)[mod_x and mod_y]
    return distance

lifespan, max_amount = 4, 0
for item in permutations([(1,1), (2,2), (3,3)]):
    lifespan_local, current = lifespan - distance((0,0), item[0]), 1
    for j in range(len(item) - 1):
        lifespan_local -= distance(item[j], item[j + 1])
        current += (0, 1)[lifespan_local > 0]
    max_amount = max(current, max_amount)
print max_amount

สวัสดีและยินดีต้อนรับสู่ PPCG! คุณสามารถสร้างและcurrent c ll m
NoOneIsHere

ว้าวขอบคุณ! พลาดหนึ่ง
Gmodjackass

ในความคิดเห็น OP ขอให้จัดการได้มากถึง 1,000 หมู่บ้าน แต่คำตอบใด ๆ ที่สร้างและจัดเก็บการเปลี่ยนแปลงทั้งหมดจะล้มเหลวแม้แต่ 15 หมู่บ้าน (ประมาณ 1,300 ล้านการเปลี่ยนลำดับ)
edc65

จะมองเข้าไปในบางจุดขอบคุณสำหรับหัวขึ้น ฉันไม่ได้อ่านความคิดเห็นเพราะมีหลายคน
Gmodjackass

เสร็จแล้วโดยใช้ตัวสร้างตอนนี้แทนที่จะเก็บพีชคณิตทั้งหมดที่สร้างขึ้นในระหว่างการเดินทางควรใช้ O (n) เพื่อเปลี่ยนรูป
Gmodjackass

1

PHP, 309 ไบต์

function j($x,$y,$c,$v){if($s=array_search([$x,$y],$v))unset($v[$s]);for($c--,$i=4;$c>0&&$i--;)$m=($n=j($x+[1,0,-1,0][$i],$y+[0,1,0,-1][$i],$c,$v))>$m?$n:$m;for($c-=.5,$i=4;$c>0&&$i--;)$m=($n=j($x+[1,-1,-1,1][$i],$y+[1,1,-1,-1][$i],$c,$v))>$m?$n:$m;return$s?++$m:$m;}echo j(0,0,$argv[1],array_chunk($argv,2));

กำลังดุร้ายแน่นอนและไม่สั้นมาก ใช้เช่น:

php -r "function j($x,$y,$c,$v){if($s=array_search([$x,$y],$v))unset($v[$s]);for($c--,$i=4;$c>0&&$i--;)$m=($n=j($x+[1,0,-1,0][$i],$y+[0,1,0,-1][$i],$c,$v))>$m?$n:$m;for($c-=.5,$i=4;$c>0&&$i--;)$m=($n=j($x+[1,-1,-1,1][$i],$y+[1,1,-1,-1][$i],$c,$v))>$m?$n:$m;return$s?++$m:$m;}echo j(0,0,$argv[1],array_chunk($argv,2));" 5 1 1 2 1 3 1 4 1 5 0 5 1

ด้วยพื้นที่ว่างมากขึ้นและบันทึกไว้ในไฟล์:

<?php 
function j( $x, $y, $c, $v)
{
    if( $s = array_search( [$x,$y], $v ) )
        unset( $v[$s] );

    for( $c--, $i=4; $c>0 && $i--;)
        $m = ( $n=j($x+[1,0,-1,0][$i],$y+[0,1,0,-1][$i],$c,$v) )>$m ? $n : $m;

    for( $c-=.5, $i=4; $c>0 && $i--;)
        $m = ( $n=j($x+[1,-1,-1,1][$i],$y+[1,1,-1,-1][$i],$c,$v) )>$m ? $n : $m;

    return $s ? ++$m : $m;
}
echo j( 0, 0, $argv[1], array_chunk($argv,2) );

1

Python ขนาด 175 ไบต์

def f(c,l):
 def r(t):p=abs(t[0]-x);q=abs(t[1]-y);return p+q-.5*min(p,q)
 v=0;x,y=0,0
 while c>0 and len(l)>0:
  l.sort(key=r);c-=r(l[0]);x,y=l.pop(0)
  if c>=0:v+=1
 return v

cเป็นอายุขัยของเทียนlเป็นรายการของ tuples - พิกัดหมู่บ้านvเป็นจำนวนของหมู่บ้านที่เข้าเยี่ยมชม(x,y)เป็นคู่พิกัดของหมู่บ้านแจ็คที่มีอยู่ในปัจจุบัน

r(t)l[0]เป็นฟังก์ชั่นที่ใช้คำนวณระยะทางไปยังตำแหน่งปัจจุบันและใช้ในการเรียงลำดับรายชื่อเพื่อให้ใกล้เคียงที่สุดที่จะกลายเป็น สูตรที่ใช้คือ | Δx | + | Δy | - ขั้นต่ำ (| Δx |, | Δy |) / 2

ลองที่นี่!


1

แร็กเกต

(define (dist x1 y1 x2 y2)     ; fn to find distance between 2 pts
  (sqrt(+ (expt(- x2 x1)2)
          (expt(- y2 y1)2))))

(define (fu x1 y1 x2 y2)       ; find fuel used to move from x1 y1 to x2 y2;
  (let loop ((x1 x1)
             (y1 y1)
             (fuelUsed 0))
    (let* ((d1 (dist (add1 x1) y1 x2 y2))        ; horizontal movement
           (d2 (dist x1 (add1 y1) x2 y2))        ; vertical movement
           (d3 (dist (add1 x1) (add1 y1) x2 y2)) ; diagonal movement
           (m (min d1 d2 d3))) ; find which of above leads to min remaining distance; 
      (cond 
        [(or (= d2 0)(= d1 0)) (add1 fuelUsed)]
        [(= d3 0) (+ 1.5 fuelUsed)]
        [(= m d1) (loop (add1 x1) y1 (add1 fuelUsed))]
        [(= m d2) (loop x1 (add1 y1) (add1 fuelUsed))]
        [(= m d3) (loop (add1 x1) (add1 y1) (+ 1.5 fuelUsed))]))))

(define (f a l)
  (define u (for/list ((i l))
    (fu 0 0 (list-ref i 0) (list-ref i 1))))  ; find fuel used for each point; 
  (for/last ((i u)(n (in-naturals)) #:final (>= i a))
    n))

การทดสอบ:

(f 4 '((1 1) (2 2) (3 3))) ;-> 2
(f 5 '((1 1) (2 1) (3 1) (4 1) (5 0) (5 1))) ;-> 4

เอาท์พุท:

2
4

อย่างไรก็ตามโค้ดข้างต้นไม่สามารถใช้ได้กับค่าลบของ x และ y

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