Problemi di zucca in viaggio


23

Sfondo:

Jack è una zucca che ama viziare i cittadini dei villaggi vicino alla sua zolla di zucca ogni Halloween. Tuttavia, ogni anno dopo che qualcuno accende la candela dentro di sé, ha un tempo limitato per spaventare tutti prima che la candela si spenga, quindi non è in grado di spaventare altri abitanti del villaggio perché nessuno può vederlo. Negli anni passati, è stato in grado di spaventare solo una piccola quantità di villaggi a causa del suo scarso processo decisionale, ma ora che avrà te per aiutarlo, sarà in grado di spaventare quanti più villaggi possibile!

Compito:

Dato un elenco di località del villaggio e una durata della candela, produce il numero massimo di villaggi che Jack può visitare. Non è necessario stampare il percorso stesso.

Ingresso:

La durata della candela e un elenco delle posizioni dei villaggi in un sistema di coordinate cartesiane. La patch di zucca da cui proviene Jack sarà sempre a 0,0. È possibile formattare l'input nel modo desiderato. Per semplificare i movimenti di Jack, può muovere solo in orizzontale, in verticale o in diagonale, il che significa che la sua candela perderà 1 o 1,5 unità (prende un po 'più in diagonale) unità di vita ad ogni mossa. La candela si spegne quando la durata della vita è inferiore o uguale a 0.

Produzione:

Un numero intero pari al numero massimo di villaggi che Jack può visitare prima che la candela si spenga.

Regole:

Questo è , quindi vince il codice più breve in byte. Non sono ammesse scappatoie standard.

Casi test:

// 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
Ridacchiando al titolo
Luis Mendo,

3
"Semplificare i movimenti di Jack" è un po 'ironico, ora è molto più difficile: D
PurkkaKoodari,

1
Penso che il tuo primo caso dovrebbe essere 3 se non sbaglio
Numberknot

1
@Numberknot No, una volta che un villaggio ha avuto paura non cadranno per lo stesso trucco, può spaventare ogni villaggio solo una volta.
Yodle,

5
Questo è un problema N-Pumpkin Hard, quindi in generale il numero massimo di villaggi potrebbe essere difficile da trovare. C'è un numero massimo di villaggi?
edc65,

Risposte:


9

Gelatina, 30 29 27 25 byte

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

Provalo online!

Apparentemente il prodotto punto di Jelly ignora semplicemente una mancata corrispondenza delle dimensioni dell'elenco e non moltiplica gli elementi extra dell'altro array, ma li aggiunge semplicemente. Elimina 2 byte.

Spiegazione

_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

In un commento, richiesta di OP per gestire fino a 1000 villaggi. Ma qualsiasi risposta che generi e immagazzini tutte le permutazioni fallirà anche 15 villaggi (~ 1300 miliardi di permutazioni)
edc65,

@ edc65 Da nessuna parte si dice che i casi così grandi debbano essere testabili, purché l'algoritmo teoricamente funzioni con tempo e memoria sufficienti. (I programmi che possono effettivamente risolvere il TSP per n ≈ 1000 sono così complessi che non sarebbero più divertenti da giocare a golf.)
PurkkaKoodari,

Ok non 1000, ma nemmeno 15?
edc65,

@ edc65 Non riesco a trovare un algoritmo che sia veloce e facilmente implementabile in Jelly. Potrei cercare di creare una soluzione più efficiente (ad es. Held-Karp) in un'altra lingua. A proposito, nessuna delle risposte usa algoritmi veramente veloci; quello JS è migliore, ma lento se ci sono molte città nel raggio di azione.
PurkkaKoodari,

5

Java 7, 206 201 byte

Grazie a @KevinCruijssen per aver salvato 5 byte

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
Bello, bravo a includere la forma "ungolfed". Anche se se lo trasformassi, penso che il revisore del codice non lo chiamerebbe non golfato. ;)
Wildcard il

+1. Una cosa al golf: usi i-xdue o b[c]-ydue volte, quindi puoi aggiungere ,tgli ints e quindi usare questo: Math.sqrt((t=i-x)*t+(t=b[c]-y)*t)*1invece di Math.sqrt((i-x)*(i-x)+(b[c]-y)*(b[c]-y))*1.
Kevin Cruijssen,

Come potrebbe funzionare nel caso generale?
edc65,

3

Scala, 196 byte

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

Funzione ricorsiva anonima, il parametro sè la durata della candela, il parametro lè l'elenco delle coordinate del villaggio.

Una prima ricerca della profondità , che si interrompe quando la distanza raggiunge la durata della candela

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

Meno golfisti vedi lo snippet di seguito

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


3

MATL , 27 byte

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

EDIT (26 nov 2016): a causa di cambiamenti nella Xlfunzione, deve essere sostituito nel codice sopra 2$X>. I collegamenti sottostanti incorporano tale modifica.

Provalo online! Oppure verifica tutti i casi di test .

Spiegazione

La distanza della zucca tra due città separate Δ x e Δ y in ciascuna coordinata può essere ottenuta come (| Δ x | + | Δ y | + max (| Δ x |, | Δ y |)) / 2.

Il codice segue questi passaggi:

  1. Generare tutte le permutazioni delle coordinate xe delle coordinate y e anteporre a a ciascuno 0. Ogni permutazione rappresenta un possibile percorso.
  2. Calcola le differenze consecutive consecutive per ciascun percorso (sono | Δ x | e | Δ y | sopra).
  3. Ottieni la distanza della zucca per ogni passaggio di ogni percorso.
  4. Calcola la somma cumulativa delle distanze per ciascun percorso.
  5. Trova, per ciascun percorso, il numero di passi prima che la distanza accumulata raggiunga la durata della vita del chandle.
  6. Prendi il massimo di quanto sopra.

Codice commentato:

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 può davvero generare tutte le permutazioni di 1000 (x, y) coppie?
edc65,

@ edc65 No, è troppo (ci sono oltre 10 ^ 2500 permutazioni di 1000 elementi). Non credo che una lingua possa farlo
Luis Mendo,

In un commento, richiesta di OP per gestire fino a 1000 villaggi. Ma qualsiasi risposta che generi e immagazzini tutte le permutazioni fallirà anche 15 villaggi (~ 1300 miliardi di permutazioni)
edc65,

@ edc65 Ah, capisco. 1000 villaggi sembrano irrealistici se il problema è NP-difficile, come sembra essere
Luis Mendo,

2

Python 2.7 , 422 byte

grazie a NoOneIsHere per aver sottolineato ulteriori miglioramenti!

grazie a edc65 per aver notato di non salvare l'elenco ma usare invece iteratori!

Provalo 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

Spiegazione:

La funzione calcola la distanza tra due punti secondo le regole date, il ciclo scorre attraverso tutte le permutazioni generate dal generatore dell'input e calcola la distanza, se la distanza è inferiore alla durata della candela la sottrae e aggiunge il posto al contatore, se quel contatore è maggiore del massimo corrente, lo sostituisce.

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

Ciao e benvenuto in PPCG! Puoi fare current c, e ll m.
NoOneIsHere

Wow grazie! perso quello
Gmodjackass il

In un commento, richiesta di OP per gestire fino a 1000 villaggi. Ma qualsiasi risposta che generi e immagazzini tutte le permutazioni fallirà anche 15 villaggi (~ 1300 miliardi di permutazioni)
edc65,

lo esaminerò ad un certo punto, grazie per il testa a testa. Non ho davvero letto i commenti perché ce ne sono molti.
Gmodjackass,

fatto, usando il generatore ora, invece di memorizzare tutte le permutazioni che le genera in movimento, dovrebbe usare circa O (n) per la permutazione.
Gmodjackass,

1

PHP, 309 byte

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

Forza assolutamente bruta e nemmeno molto corta. Usa come:

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

Con più spazi bianchi e salvati in un file:

<?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 byte

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è la durata della candela, lè un elenco di tuple - coordinate del villaggio, vè il numero di villaggi visitati, (x,y)è una coppia di coordinate del villaggio in cui si trova attualmente Jack.

r(t)è una funzione che calcola la distanza dalla posizione corrente e viene utilizzata per ordinare l'elenco in modo che diventi il ​​più vicino l[0]. La formula utilizzata è | Δx | + | Δy | - min (| Δx |, | Δy |) / 2.

Provalo qui!


1

Racchetta

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

test:

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

Produzione:

2
4

Tuttavia, il codice sopra non funziona per i valori negativi di xe y.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.