Problem z dyni w podróży

23

Tło:

Jack to dynia, która co Halloween lubi straszyć mieszkańców wsi w pobliżu swojej łaty z dyni. Jednak każdego roku po tym, jak ktoś zapali w nim świecę, ma on ograniczoną ilość czasu, aby przestraszyć wszystkich, zanim świeca się wypali, a tym samym nie jest w stanie przestraszyć więcej wieśniaków, ponieważ nikt go nie widzi. W ostatnich latach był w stanie wystraszyć tylko niewielką liczbę wiosek z powodu złego podejmowania decyzji, ale teraz, gdy ma cię do pomocy, będzie w stanie wystraszyć jak najwięcej wiosek!

Zadanie:

Biorąc pod uwagę listę miejscowości i długość życia świec, wypisz maksymalną liczbę wiosek, które Jack może odwiedzić. Nie musisz drukować samej ścieżki.

Wkład:

Żywotność świecy i lista miejscowości w kartezjańskim układzie współrzędnych. Naszywka z dyni, z której pochodzi Jack, zawsze będzie wynosić 0,0. Możesz sformatować dane wejściowe w dowolny sposób. Aby uprościć ruchy Jacka, może on poruszać się tylko w poziomie, w pionie lub po przekątnej, co oznacza, że ​​jego świeca straci 1 lub 1,5 (zabiera nieco dłużej po przekątnej) jednostki życia przy każdym ruchu. Świeca wypala się, gdy żywotność jest mniejsza lub równa 0.

Wydajność:

Liczba całkowita równa maksymalnej liczbie wiosek, które Jack może odwiedzić przed wypaleniem świecy.

Zasady:

To jest , więc wygrywa najkrótszy kod w bajtach. Standardowe luki są niedozwolone.

Przypadki testowe:

// 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
Jodła
źródło
9
Chichocząc z tytułu
Luis Mendo
3
„Aby uprościć ruchy Jacka” jest dość ironiczne, jest teraz o wiele trudniejsze: D
PurkkaKoodari
1
Myślę, że twój pierwszy przypadek powinien wynosić 3, jeśli się nie mylę
Numberknot
1
@Numberknot Nie, gdy wioska się przestraszy, nie wpadnie na tę samą sztuczkę, może przestraszyć każdą wioskę tylko raz.
Yodle
5
Jest to trudny problem z N-Pumpkin, więc ogólnie trudno jest znaleźć maksymalną liczbę wiosek. Istnieje maksymalna liczba wiosek?
edc65

Odpowiedzi:

9

Galaretka, 30 29 27 25 bajtów

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

Wypróbuj online!

Najwyraźniej produkt kropkowy Jelly po prostu ignoruje niedopasowanie wielkości listy i nie zwielokrotnia dodatkowych elementów drugiej tablicy, po prostu je dodaje. Ogolił 2 bajty.

Wyjaśnienie

_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
PurkkaKoodari
źródło
W komentarzu wniosek OP o zarządzanie do 1000 wiosek. Ale każda odpowiedź, która generuje i przechowuje wszystkie permutacje, zawiedzie nawet 15 wiosek (~ 1300 miliardów permutacji)
edc65 27.10.16
@ edc65 Nigdzie nie jest powiedziane, że przypadki tak duże muszą być testowalne, o ile algorytm teoretycznie działa przy wystarczającej ilości czasu i pamięci. (Programy, które potrafią rozwiązać TSP dla n ≈ 1000, są tak złożone , że nie byłoby już fajnie grać w golfa.)
PurkkaKoodari,
Ok nie 1000, ale nawet 15?
edc65
@ edc65 Nie mogę znaleźć algorytmu, który byłby szybki i wyglądałby łatwo do wdrożenia w Jelly. Może zastanowię się nad stworzeniem bardziej wydajnego rozwiązania (np. Held-Karp) w innym języku. BTW, żadna z odpowiedzi nie używa faktycznie szybkich algorytmów; JS jeden jest lepszy, ale powolny, jeśli w zasięgu jest wiele miast.
PurkkaKoodari
5

Java 7, 206 201 bajtów

Dzięki @KevinCruijssen za oszczędność 5 bajtów

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;}

Bez golfa

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 ;

}

   }
Numberknot
źródło
2
Fajnie, dobrze włączając w to formę „bez golfa”. Chociaż jeśli to włączysz, myślę, że recenzent kodu nie nazwałby tego nieprzyzwyczajonym. ;)
Wildcard,
+1. Jedna rzecz do gry w golfa: używasz i-xdwa i b[c]-ydwa razy, więc możesz dodać ,tdo ints, a następnie użyć tego: Math.sqrt((t=i-x)*t+(t=b[c]-y)*t)*1zamiast Math.sqrt((i-x)*(i-x)+(b[c]-y)*(b[c]-y))*1.
Kevin Cruijssen
Jak może to działać w ogólnym przypadku?
edc65
3

Scala, 196 bajtów

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

Nie golfowany:

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
}

Objaśnienie:

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
corvus_192
źródło
3

JavaScript (ES6), 145

Anonimowa funkcja rekurencyjna, parametrem sjest żywotność świecy, parametrem ljest lista współrzędnych wioski.

Depth First Search , zatrzymując się, gdy odległość reachs żywotność świec

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

Mniej grał w golfa, patrz poniższy fragment

Test

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

edc65
źródło
3

MATL , 27 bajtów

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

EDYCJA (26 listopada 2016 r.): Ze względu na zmiany Xlfunkcji należy ją zastąpić w powyższym kodzie przez 2$X>. Poniższe linki zawierają tę modyfikację.

Wypróbuj online! Lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie

Odległość dyni między miastami oddzielone Δ x i Δ Y w każdej współrzędnej można otrzymać jako (| Δ x | + | Δ y | + max (| Δ x |, | Δ r |)) / 2.

Kod wykonuje następujące kroki:

  1. Wygeneruj wszystkie permutacje współrzędnych xi współrzędnych y , a następnie wstaw do a 0. Każde permutacja reprezentuje możliwą ścieżkę.
  2. Oblicz bezwzględne kolejne różnice dla każdej ścieżki (są to | Δ x | i | Δ y | powyżej).
  3. Uzyskaj odległość dyni dla każdego kroku na każdej ścieżce.
  4. Oblicz skumulowaną sumę odległości dla każdej ścieżki.
  5. Znajdź, dla każdej ścieżki, liczbę kroków, zanim zakumulowana odległość osiągnie żywotność żyrandola.
  6. Weź maksimum z powyższych.

Skomentowany kod:

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
Luis Mendo
źródło
czy MATL naprawdę może wygenerować całą permutację par 1000 (x, y)?
edc65,
@ edc65 Nie, to za dużo (istnieje ponad 10 ^ 2500 kombinacji 1000 elementów). Nie sądzę, żeby jakikolwiek język mógł
Luis Mendo,
W komentarzu wniosek OP o zarządzanie do 1000 wiosek. Ale każda odpowiedź, która generuje i przechowuje wszystkie permutacje, zawiedzie nawet 15 wiosek (~ 1300 miliardów permutacji)
edc65 27.10.16
@ edc65 Ah, rozumiem. 1000 wiosek wydaje się nierealistycznych, jeśli problem jest trudny jak na NP, jak się wydaje
Luis Mendo
2

Python 2.7 , 422 bajty

dzięki NoOneIsHere za wskazanie dodatkowych ulepszeń!

dzięki edc65 za informację, że nie zapisujesz listy, ale zamiast tego używaj iteratorów!

Wypróbuj online!

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

Wyjaśnienie:

Funkcja oblicza odległość między dwoma punktami zgodnie z podanymi regułami, pętla iteruje przez wszystkie permutacje generowane przez generator danych wejściowych i oblicza odległość, jeśli odległość jest mniejsza niż długość życia świecy, odejmuje ją i dodaje miejsce do licznik, jeśli ten licznik jest większy niż bieżące maksimum, zastępuje go.

bez golfa:

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
Gmodjackass
źródło
Witaj i witaj w PPCG! Możesz zrobić current ci ll m.
NoOneIsHere
wow, dzięki! przegapiłem ten
Gmodjackass,
W komentarzu wniosek OP o zarządzanie do 1000 wiosek. Ale każda odpowiedź, która generuje i przechowuje wszystkie permutacje, zawiedzie nawet 15 wiosek (~ 1300 miliardów permutacji)
edc65 27.10.16
przyjrzy się temu w pewnym momencie, dzięki za podniesienie głowy. Tak naprawdę nie czytałem komentarzy, ponieważ jest ich wiele.
Gmodjackass
zrobione, używając generatora teraz, zamiast przechowywać wszystkie permutacje, które generuje je w ruchu, należy użyć około O (n) dla permutacji.
Gmodjackass
1

PHP, 309 bajtów

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

Absolutnie brutalna siła, a nawet niezbyt krótka. Użyj jak:

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

Z większą ilością białych znaków i zapisanych w pliku:

<?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) );
użytkownik59178
źródło
1

Python, 175 bajtów

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

cto długość życia świecy, lto lista krotek - współrzędne wioski, vliczba odwiedzonych wiosek, (x,y)para współrzędnych wioski, w której Jack jest obecnie.

r(t)to funkcja, która oblicza odległość do aktualnej pozycji i służy do sortowania listy, aby stała się najbliższa l[0]. Zastosowana formuła to | Δx | + | Δy | - min (| Δx |, | Δy |) / 2.

Wypróbuj tutaj!

AlexRacer
źródło
1

Rakieta

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

Testowanie:

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

Wydajność:

2
4

Powyższy kod nie działa jednak dla ujemnych wartości xiy.

rnso
źródło