Vấn đề bí ngô du lịch


23

Lý lịch:

Jack là một quả bí ngô thích làm điên đảo các công dân của các ngôi làng gần miếng bí ngô của mình mỗi dịp Halloween. Tuy nhiên, mỗi năm sau khi ai đó thắp ngọn nến bên trong anh ta, anh ta có một khoảng thời gian giới hạn để làm mọi người hoảng sợ trước khi ngọn nến cháy hết, do đó không thể làm bất kỳ dân làng nào thêm nữa vì không ai có thể nhìn thấy anh ta. Trong những năm qua, anh ta chỉ có thể tạo ra một số ít làng do quyết định kém của mình, nhưng bây giờ anh ta có bạn để giúp anh ta, anh ta sẽ có thể tạo ra nhiều ngôi làng nhất có thể!

Bài tập:

Đưa ra một danh sách các địa điểm làng và tuổi thọ của nến, hãy đưa ra số lượng làng tối đa mà Jack có thể ghé thăm. Bạn không phải tự in đường dẫn.

Đầu vào:

Tuổi thọ của nến và danh sách các vị trí làng trong hệ thống tọa độ của Cartesian. Miếng vá bí ngô Jack có nguồn gốc từ sẽ luôn ở mức 0,0. Bạn có thể định dạng đầu vào trong bất cứ cách nào bạn muốn. Để đơn giản hóa các chuyển động của Jack, anh ta chỉ có thể di chuyển theo chiều ngang, chiều dọc hoặc đường chéo, nghĩa là cây nến của anh ta sẽ mất 1 hoặc 1,5 (anh ta mất một chút thời gian theo đường chéo) mỗi lần di chuyển. Nến cháy hết khi tuổi thọ nhỏ hơn hoặc bằng 0.

Đầu ra:

Một số nguyên bằng số làng tối đa mà Jack có thể truy cập trước khi nến cháy hết.

Quy tắc:

Đây là , vì vậy mã ngắn nhất tính bằng byte thắng. Sơ hở tiêu chuẩn không được phép.

Các trường hợp thử nghiệm:

// 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
Cười khúc khích với tiêu đề
Luis Mendo

3
"Để đơn giản hóa các chuyển động của Jack" thật là mỉa mai, điều này bây giờ khó khăn hơn nhiều: D
PurkkaKoodari

1
Tôi nghĩ rằng trường hợp đầu ra của bạn phải là 3 nếu tôi không sai
Numberjack

1
@Numberizard Không, một khi một ngôi làng đã sợ hãi họ sẽ không rơi vào cùng một mánh khóe, anh ta chỉ có thể sợ mỗi làng một lần.
Yodle

5
Đây là một vấn đề N-Pumpkin Hard, vì vậy nói chung, số lượng làng tối đa có thể khó tìm. Có số lượng làng tối đa?
edc65

Câu trả lời:


9

Thạch, 30 29 27 25 byte

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

Hãy thử trực tuyến!

Rõ ràng sản phẩm chấm của Jelly chỉ bỏ qua sự không phù hợp về kích thước danh sách và không nhân các phần tử phụ của mảng khác, chỉ cần thêm chúng. Tắt 2 byte.

Giải trình

_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

Trong một bình luận, OP yêu cầu quản lý tới 1000 ngôi làng. Nhưng bất kỳ câu trả lời nào tạo ra và lưu trữ tất cả các hoán vị sẽ thất bại ngay cả 15 ngôi làng (~ 1300 tỷ hoán vị)
edc65

@ edc65 Không nơi nào nói rằng các trường hợp cần phải kiểm tra được, miễn là thuật toán hoạt động theo lý thuyết với đủ thời gian và bộ nhớ. (Các chương trình thực sự có thể giải quyết TSP cho 1000 đô la rất phức tạp, họ sẽ không vui chơi golf nữa.)
PurkkaKoodari

Ok không 1000, nhưng thậm chí không 15?
edc65

@ edc65 Tôi không thể tìm thấy một thuật toán nào có thể nhanh chóng và có thể dễ dàng thực hiện trong Jelly. Tôi có thể xem xét việc tạo ra một giải pháp hiệu quả hơn (ví dụ Held-Karp) bằng ngôn ngữ khác. BTW, không có câu trả lời nào sử dụng thuật toán thực sự nhanh; một trong những JS là tốt hơn, nhưng chậm nếu có nhiều thành phố trong phạm vi.
PurkkaKoodari

5

Java 7, 206 201 byte

Cảm ơn @KevinCruijssen đã lưu 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;}

Bị đánh cắp

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
Đẹp, tốt bao gồm cả hình thức "vô danh". Mặc dù nếu bạn bật nó, tôi nghĩ rằng người đánh giá mã sẽ không gọi nó là vô căn cứ. ;)
tự đại diện

+1. Một điều để chơi golf: Bạn sử dụng i-xhai lần và b[c]-yhai lần, vì vậy bạn có thể thêm ,tvào ints, và sau đó sử dụng điều này: Math.sqrt((t=i-x)*t+(t=b[c]-y)*t)*1thay vì Math.sqrt((i-x)*(i-x)+(b[c]-y)*(b[c]-y))*1.
Kevin Cruijssen

Làm thế nào điều này có thể làm việc trong trường hợp chung?
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

Ung dung:

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
}

Giải thích:

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

Hàm đệ quy ẩn danh, tham số slà tuổi thọ của nến, tham số llà danh sách tọa độ làng.

Một Depth First Search , dừng lại khi khoảng cách đạt từ tuổi thọ nến

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

Ít chơi gôn hơn xem đoạn trích dưới đây

Kiểm tra

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): Do thay đổi Xlchức năng, nó phải được thay thế trong đoạn mã trên bằng 2$X>. Các liên kết dưới đây kết hợp sửa đổi đó.

Hãy thử trực tuyến! Hoặc xác minh tất cả các trường hợp thử nghiệm .

Giải trình

Các khoảng cách bí giữa hai thành phố tách Δ x và Δ y trong từng phối hợp có thể thu được như (| Δ x | + | Δ y | + max (| Δ x |, | Δ y |)) / 2.

Mã theo các bước sau:

  1. Tạo tất cả các hoán vị của tọa độ x và tọa độ y và thêm a cho mỗi 0. Mỗi hoán vị đại diện cho một đường dẫn có thể.
  2. Tính toán sự khác biệt liên tiếp tuyệt đối cho mỗi đường dẫn (đây là | x | và | y | ở trên).
  3. Có được khoảng cách bí ngô cho mỗi bước của mỗi con đường.
  4. Tính tổng tích lũy khoảng cách cho mỗi đường dẫn.
  5. Tìm, đối với mỗi đường dẫn, số bước trước khi khoảng cách tích lũy đạt đến tuổi thọ chandle.
  6. Lấy tối đa của trên.

Mã nhận xét:

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 thực sự có thể tạo ra tất cả các hoán vị của các cặp 1000 (x, y) không?
edc65

@ edc65 Không, đó là quá nhiều (có hơn 10 ^ 2500 hoán vị của 1000 yếu tố). Tôi không nghĩ bất kỳ ngôn ngữ nào cũng có thể
Luis Mendo

Trong một bình luận, OP yêu cầu quản lý tới 1000 ngôi làng. Nhưng bất kỳ câu trả lời nào tạo ra và lưu trữ tất cả các hoán vị sẽ thất bại ngay cả 15 ngôi làng (~ 1300 tỷ hoán vị)
edc65

@ edc65 À, tôi hiểu rồi. 1000 ngôi làng dường như không thực tế nếu vấn đề là NP-hard, như có vẻ là
Luis Mendo

2

Python 2.7 , 422 byte

cảm ơn NoOneIsHere đã chỉ ra những cải tiến bổ sung!

cảm ơn edc65 vì đã lưu ý không lưu danh sách mà thay vào đó hãy sử dụng các trình vòng lặp!

Hãy thử trực tuyến!

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

Giải trình:

Hàm tính toán khoảng cách giữa hai điểm theo quy tắc đã cho, vòng lặp lặp qua tất cả các hoán vị được tạo bởi bộ tạo đầu vào và tính khoảng cách, nếu khoảng cách nhỏ hơn tuổi thọ của nến, nó sẽ trừ đi và thêm vị trí vào bộ đếm, nếu bộ đếm đó lớn hơn mức tối đa hiện tại, nó sẽ thay thế nó.

vô dụng:

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

Xin chào, và chào mừng đến với PPCG! Bạn có thể làm current c, và ll m.
NoOneIsHãy

Ồ cảm ơn nhé! đã bỏ lỡ cái đó
Gmodjackass

Trong một bình luận, OP yêu cầu quản lý tới 1000 ngôi làng. Nhưng bất kỳ câu trả lời nào tạo ra và lưu trữ tất cả các hoán vị sẽ thất bại ngay cả 15 ngôi làng (~ 1300 tỷ hoán vị)
edc65

sẽ nhìn vào đó tại một số điểm, cảm ơn cho những người đứng đầu. Tôi đã không thực sự đọc các bình luận bởi vì có rất nhiều trong số họ.
Gmodjackass

xong, sử dụng trình tạo ngay bây giờ, thay vì lưu trữ tất cả các hoán vị mà nó tạo ra khi đang di chuyển, nên sử dụng khoảng O (n) cho hoán vị.
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));

Hoàn toàn vũ phu và thậm chí không quá ngắn. Sử dụng như:

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

Với nhiều khoảng trắng hơn và được lưu trong một tệp:

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

clà tuổi thọ của ngọn nến, llà một danh sách các bộ dữ liệu - tọa độ làng, vlà số làng được thăm, (x,y)là cặp tọa độ của làng Jack hiện đang ở.

r(t)là một hàm tính toán khoảng cách đến vị trí hiện tại và được sử dụng để sắp xếp danh sách sao cho gần nhất trở thành l[0]. Công thức được sử dụng là | x | + | Δy | - phút (| Δx |, | Δy |) / 2.

Hãy thử nó ở đây!


1

Vợt

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

Kiểm tra:

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

Đầu ra:

2
4

Tuy nhiên, mã trên không hoạt động cho các giá trị âm của x và y.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.