Проблема подорожей з гарбузом


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
@Numberknot Ні, як тільки село злякалося, що вони не потраплять на один і той же трюк, він може тільки один раз налякати кожне село.
Йодл

5
Це важка проблема з N-гарбузами, тому в цілому максимум сіл може бути важко знайти. Є максимальна кількість сіл?
edc65

Відповіді:


9

Желе, 30 29 27 25 байт

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

Спробуйте в Інтернеті!

Мабуть, точковий продукт Jelly просто ігнорує невідповідність розміру списку і не примножує зайві елементи іншого масиву, а лише додає їх. Голіть 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

У коментарі ОП запит на управління до 1000 сіл. Але будь-яка відповідь, що генерує та зберігає всі перестановки, не підведе навіть 15 сіл (~ 1300 мільярдів перестановок)
edc65

@ edc65 Ніде не сказано, що великі випадки потребують перевірки, якщо алгоритм теоретично працює, даючи достатньо часу та пам'яті. (Програми, які насправді можуть вирішити TSP для n ≈ 1000, є настільки складними, що більше не
забавлятимуться

Гаразд не 1000, але навіть не 15?
edc65

@ edc65 Я не можу знайти алгоритм, який був би швидким і виглядав легко реалізованим в Jelly. Я можу розглянути можливість більш ефективного рішення (наприклад, Held-Karp) іншою мовою. До речі, жодна з відповідей не використовує фактично швидкі алгоритми; 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;}

Безумовно

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
Приємно, добре включаючи форму "без вольфу". Хоча якби ви це перетворили, я думаю, що рецензент коду не назвав би це неробочим. ;)
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

Безголівки:

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
}

Пояснення:

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- список координат села.

Depth First Search , зупинка , коли відстань reachs свічки термін служби

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)))

Менше гольфу дивіться фрагмент нижче

Тест

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>

EDIT (26 листопада 2016 р.): Через зміни Xlфункції її потрібно замінити у наведеному вище коді на 2$X>. Посилання нижче містять цю модифікацію.

Спробуйте в Інтернеті! Або перевірити всі тестові випадки .

Пояснення

Відстань гарбуза між двома містами розділені Д х і Д у в кожен з яких може бути отримана як координати (| Д х | + | Д у | + тах (| Д х |, | Д у |)) / 2.

Код виконує наступні кроки:

  1. Створіть усі перестановки з x координат і y координат, і додайте до кожної 0. Кожна перестановка являє собою можливий шлях.
  2. Обчисліть абсолютні різниці підряд для кожного шляху (це | Δ x | та | Δ y | вище).
  3. Отримайте відстань гарбуза для кожного кроку кожної стежки.
  4. Обчисліть сукупну суму відстаней для кожного шляху.
  5. Знайдіть для кожної стежки кількість кроків до того, як накопичена відстань досягне тривалості життя каналу.
  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 справді генерувати всю перестановку з 1000 (x, y) пар?
edc65

@ edc65 Ні, це занадто багато (є понад 10 ^ 2500 перестановок з 1000 елементів). Я не думаю, що жодна мова не може
Луїс Мендо

У коментарі ОП запит на управління до 1000 сіл. Але будь-яка відповідь, що генерує та зберігає всі перестановки, не підведе навіть 15 сіл (~ 1300 мільярдів перестановок)
edc65

@ edc65 Ах, бачу. 1000 сіл здаються нереальними, якщо проблема непроста, як здається,
Луїс Мендо

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

Пояснення:

Функція обчислює відстань між двома точками відповідно до заданих правил, цикл проходить через усі перестановки, що генеруються генератором вводу, і обчислює відстань, якщо відстань менша за тривалість життя свічки, вона віднімає її і додає місце до лічильник, якщо цей лічильник більший за поточний макс, він його замінює.

неозорений:

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

У коментарі ОП запит на управління до 1000 сіл. Але будь-яка відповідь, що генерує та зберігає всі перестановки, не підведе навіть 15 сіл (~ 1300 мільярдів перестановок)
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

Пітон, 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це список кортежів - координати села, 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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.