Kabak Problemi


23

Arka fon:

Jack, her Cadılar Bayramında kabak yamalarının yakınındaki köylerin vatandaşlarını korkutmaktan hoşlanan bir balkabağıdır. Bununla birlikte, bir yıl onun içindeki mumu yaktıktan sonra, mum yanmadan önce herkesi korkutmak için sınırlı bir süreye sahiptir, bu nedenle kimse onu göremez, çünkü daha fazla köylü korkutmaz. Geçtiğimiz yıllarda, karar vermemesi nedeniyle yalnızca az miktarda köyü korkutabildi, ama şimdi ona yardım edebileceğinden, mümkün olduğu kadar çok köyü korkutabilir!

Görev:

Köy yerlerinin bir listesi ve bir mum ömrü göz önüne alındığında, Jack'in ziyaret edebileceği maksimum köy sayısı çıktı. Yolu yazdırmanız gerekmez.

Giriş:

Mumun ömrü ve Kartezyen koordinat sisteminde köy yerlerinin bir listesi. Jack'ten kaynaklanan balkabağı yama her zaman 0,0 'da olacaktır. Girişi istediğiniz şekilde biçimlendirebilirsiniz. Jack'in hareketlerini basitleştirmek için, yalnızca yatay, dikey veya çapraz olarak hareket edebilir, bu da mumunun her hareketinde 1 veya 1.5 (çapraz olarak biraz daha uzun sürer) yaşam birimlerini kaybedeceği anlamına gelir. Mum, ömrü 0'a eşit veya daha küçük olduğunda yanar.

Çıktı:

Mum yanmadan önce Jack'in ziyaret edebileceği maksimum köy sayısına eşit bir tam sayı.

Kurallar:

Bu , bayt cinsinden en kısa kod kazanır. Standart boşluklara izin verilmez.

Test durumları:

// 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
Başlığında
kıkırdayarak

3
"Jack'in hareketlerini basitleştirmek için" biraz ironik, bu şimdi çok daha zor: D
PurkkaKoodari

1
Bence yanlış yaptığım ilk dava çıktısının 3 olması gerekiyor
Sayı 18.02'de

1
@Hayır Hayır, bir köy korktuktan sonra aynı numaraya düşmeyecek, her köyü sadece bir kez korkutabilir.
Yodle

5
Bu bir N-Pumpkin Hard problemidir, bu nedenle genel olarak maksimum köy sayısını bulmak zor olabilir. Azami köy var mı?
edc65 25:16

Yanıtlar:


9

Jöle, 30 29 27 25 bayt

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

Çevrimiçi deneyin!

Görünüşe göre Jelly'in nokta ürünü sadece liste büyüklüğündeki bir uyuşmazlığı görmezden geliyor ve diğer dizinin ekstra öğelerini çarpmıyor, sadece ekliyor. 2 bayt Tıraş.

açıklama

_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

Bir yorumda, OP 1000'e kadar köyü yönetme talebinde bulundu. Ancak tüm
izinleri

@ edc65 Hiçbir yerde, algoritma teorik olarak yeterli zaman ve bellek verilmiş olarak çalıştığı sürece, test edilebilecek büyüklüklere sahip olduğu söylenemez. (N = 1000 için
TSP'yi

Tamam 1000 değil, 15 bile değil mi?
edc65

@ edc65 Hızlı ve kolayca Jelly'de uygulanabilir görünen bir algoritma bulamıyorum . Başka bir dilde daha verimli bir çözüm (örneğin Held-Karp) yapmaya çalışabilirim. BTW, cevapların hiçbiri aslında hızlı algoritmalar kullanmaz; JS biri daha iyi, ancak menzildeki birçok şehir varsa yavaş.
PurkkaKoodari

5

Java 7, 206 201 bayt

5 byte'ı kaydettiği için @KevinCruijssen'e teşekkürler

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
Güzel, "ungolfed" formunu eklemek güzel. Ne düşünüyorum kod gözden edeceğini dönerse rağmen değil o ungolfed diyoruz. ;)
Wildcard

+1. Golf oynamak için bir şey: i-xİki ve b[c]-yiki kez kullanıyorsunuz, bu yüzden ,tint'leri ekleyebilir ve sonra bunu kullanabilirsiniz: Math.sqrt((t=i-x)*t+(t=b[c]-y)*t)*1yerine Math.sqrt((i-x)*(i-x)+(b[c]-y)*(b[c]-y))*1.
Kevin Cruijssen

Bu genel davada nasıl işe yarayabilir?
edc65

3

Scala, 196 bayt

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
}

bir açıklamasını:

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

Anonim özyinelemeli işlev, parametre smum ömrü, parametre lköy koordinat listesidir.

Mesafenin mum ömrüne ulaştığında durduğu bir Derinlik İlk Arama

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

Az golfed aşağıdaki pasajı bakın

Ölçek

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 bayt

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

EDIT (26 Kasım 2016): XlFonksiyondaki değişikliklerden dolayı yukarıdaki kod ile değiştirilmelidir 2$X>. Aşağıdaki linkler bu değişikliği içermektedir.

Çevrimiçi deneyin! Veya tüm test durumlarını doğrulayın .

açıklama

Kabak mesafesi iki şehir arasında Δ ayrılmış x ve Δ y her biri olarak elde edilebilir koordinat (| Δ x | + | Δ y | + maksimum (| Δ x |, | Δ y |)) / 2.

Kod şu adımları izler:

  1. X koordinatlarının ve y koordinatlarının tüm permütasyonlarını oluşturun ve her 0'a bir a hazırlayın. Her permütasyon olası bir yolu temsil eder.
  2. Her yol için mutlak ardışık farkları hesaplayın (bunlar | | x x | ve | Δ y | yukarıda).
  3. Her yolun her adımı için kabak mesafesini elde edin.
  4. Her yol için toplam mesafelerin toplamını hesaplayın.
  5. Her bir yol için, biriken mesafe, merdane ömrüne ulaşmadan önceki adım sayısını bulun.
  6. Yukarıdakilerin maksimumunu alın.

Yorumlanan 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

MATL gerçekten 1000 (x, y) çiftlerin tüm permütasyonlarını oluşturabilir mi?
edc65

@ edc65 Hayır, bu çok fazla (1000 öğenin 10 ^ 2500'den fazla permütasyonu var). Herhangi bir dilin yapabileceğini sanmıyorum
Luis Mendo

Bir yorumda, OP 1000'e kadar köyü yönetme talebinde bulundu. Ancak, tüm
izinleri

@ edc65 Ah, anlıyorum. Sorun NP-zor ise 1000 köy gerçekçi görünmüyor, göründüğü gibi
Luis Mendo

2

Python 2.7 , 422 bayt

NoOneIsHere'e ek iyileştirmeler gösterdiği için teşekkür ederiz!

Listeyi kaydetmediğinizi not ettiğiniz için edc65'e teşekkürler, bunun yerine yineleyicileri kullanın!

Çevrimiçi deneyin!

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

Açıklama:

Fonksiyon, verilen kurallara göre iki nokta arasındaki mesafeyi hesaplar, döngü girişin jeneratörü tarafından üretilen tüm permütasyonlar boyunca yinelenir ve eğer mesafe onu çıkardığı mumun ömründen daha az ise mesafeyi hesaplar ve yere ekler. Sayaç, bu sayaç mevcut maksimum değerden büyükse, bunun yerine kullanılır.

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

Merhaba, PPCG'ye hoş geldiniz! Yapabilir current cve ll m.
NoOneIsHere

vay, teşekkürler! bunu kaçırdım
Gmodjackass

Bir yorumda, OP 1000'e kadar köyü yönetme talebinde bulundu. Ancak, tüm
izinleri

Bir noktada buna bakacağım, kafaları için teşekkürler. Yorumları okumamıştım çünkü çoğu var.
Gmodjackass 27:16

şimdi, jeneratör kullanarak, halindeyken ürettiği tüm permütasyonları depolamak yerine, permütasyon için O (n) kullanmalıdır.
Gmodjackass

1

PHP, 309 bayt

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

Kesinlikle kaba kuvvet ve çok kısa bile değil. Gibi kullanın:

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

Daha fazla boşluk ve dosyaya kaydedilmiş olarak:

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

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

cmumun ömrü l, bir tupel listesi - köy koordinatları, vziyaret edilen köy sayısı, (x,y)Jack'in şu anda bulunduğu köyün koordinatları çifti.

r(t)geçerli konuma olan mesafeyi hesaplayan ve listeyi en yakın olacak şekilde sıralamak için kullanılan bir işlevdir l[0]. Kullanılan formül | Δx | + | Δy | - dak (| Δx |, | Δy |) / 2.

Burada dene!


1

raket

(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 yapmak:

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

Çıktı:

2
4

Bununla birlikte, yukarıdaki kod, x ve y'nin negatif değerleri için çalışmaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.