Ada Golf # 2: Eksantrik Keşişler


19

Bu bir dizi Island Golf mücadelesinde ikincisidir. Önceki meydan okuma

Issız bir adaya iki mermi geldi. Yalnızlık aramaya geldiklerinden, birbirlerinden mümkün olduğunca uzakta yaşamak istiyorlar. Aralarındaki yürüme mesafesini en üst düzeye çıkarmak için kulübelerini nerede inşa etmelidirler?

İlgili okuma

Giriş

Girişiniz, kara ve suyu temsil eden iki karakterden oluşan dikdörtgen bir ızgara olacaktır. Aşağıdaki örneklerde toprak #ve su ., ancak istediğiniz iki farklı karakteri değiştirebilirsiniz.

...........
...##......
..#####....
..#######..
.#########.
...#######.
...#####.#.
....####...
...........

Her zaman en az iki kara fayans olacaktır. Kara karolarının hepsi bitişik olacak (yani sadece bir ada var). Su fayansları da bitişik olacaktır (yani göl yoktur). Izgaranın dış sınırı tüm su kiremit olacaktır. Kara fayans olacak değil çapraz bağlanabilir: yani gibi bir şey görmek asla

....
.#..
..#.
....

Çıktı

Kodunuz, üzerinde iki kulübe yeri işaretlenmiş aynı ızgarayı çıkarmalıdır . Aşağıdaki örneklerde, kulübe konumları X ile işaretlenmiştir, ancak kara ve su karakterlerinizden farklı olduğu sürece herhangi bir karakteri değiştirebilirsiniz.

Kulübe yerleri, aralarındaki yürüyüş mesafesini en üst düzeye çıkarmak için seçilen iki kara fayans olmalıdır . Yürüme mesafesini, iki nokta arasındaki, tamamen karadaki en kısa yolun uzunluğu olarak tanımlıyoruz. Kara fayansları yatay veya dikey olarak bitişik olarak kabul edilir, ancak çapraz olarak kabul edilmez .

Yukarıdaki ada için olası bir çözüm:

...........
...X#......
..#####....
..#######..
.#########.
...#######.
...#####.X.
....####...
...........

Bu iki nokta arasındaki yürüme mesafesi, bu adadaki herhangi iki nokta arasındaki en büyük mesafe olan 11'dir. Başka bir mesafe-11 çözümü var:

...........
...##......
..X####....
..#######..
.#########.
...#######.
...#####.X.
....####...
...........

ayrıntılar

Çözümünüz tam bir program veya bir işlev olabilir . Herhangi bir varsayılan giriş ve çıkış yöntemleri kabul edilebilir.

Giriş ve çıktınız çok satırlı bir dize, bir dize listesi veya 2B bir dizi / iç içe karakter / tek karakterli dize listesi olabilir. Çıktınızın (isteğe bağlı olarak) tek bir sondaki yeni satırı olabilir. Yukarıda belirtildiği gibi, yerine üç farklı karakter kullanabilirsiniz #.X(lütfen gönderiminizde hangi karakterleri kullandığınızı belirtin).

Test senaryoları

A. Benzersiz kulübe yerleşimli adalar:

....
.##.
....

....
.XX.
....

......
......
..##..
...#..
......
......

......
......
..X#..
...X..
......
......

........
.#####..
.##..##.
.#..###.
.##..##.
........

........
.#####..
.##..##.
.#..###.
.#X..#X.
........

.........
.#####.#.
.#...#.#.
.#.###.#.
.#.....#.
.#######.
.........

.........
.#####.X.
.#...#.#.
.#.X##.#.
.#.....#.
.#######.
.........

B. Birden fazla olası çözümü olan bir ada örneği:

........
....##..
...####.
..###...
.#####..
.#####..
..##....
........

Olası çıkışlar:

........
....#X..
...####.
..###...
.#####..
.X####..
..##....
........

........
....#X..
...####.
..###...
.#####..
.#####..
..X#....
........

........
....##..
...###X.
..###...
.#####..
.X####..
..##....
........

........
....##..
...###X.
..###...
.#####..
.#####..
..X#....
........

C , bir Gist gibi büyük bir test durumu


Bu : her dilde en kısa kod kazanır.


2
Bunlar büyük küçük zorluklar (özellikle herhangi bir sınır kontrolü yapmak zorunda değilim!): Bir sonraki için sabırsızlanıyoruz!
VisualMelon

yürüme mesafesi manhattan mesafesi nedir?
Sarge Borsch

@SargeBorsch Yakından ilişkili, ancak her zaman aynı değil. Manhattan mesafesi sadece +x + Δy'dir, ancak okyanus karolarında yürüyemediğiniz için yürüme mesafesi daha uzun olabilir. (Örneğin, 'A' bölümündeki son örneğe bakın. İki X arasındaki Manhattan mesafesi 6, ancak spirali takip eden yürüme mesafesi 22'dir.)
DLosc

Yanıtlar:


5

Python 3, 249246 bayt

3 bayt tıraş edildi, teşekkürler DLosc.

Giriş ve çıkış, sırasıyla su, kulübe ve araziyi temsil eden '.', '@' Ve 'X' olan tek dizelerdir.

A='@'
def f(s):
 w=s.find('\n')+1;d=u={(k,k):0for k,c in enumerate(s)if A<c}
 while u:d.update(u);u={(k,j):d[(k,i)]+1for k,i in d for j in{i+1,i+w,i-1,i-w}if A<s[j]and(k,j)not in d}
 k,j=sorted(max(d,key=d.get))
 return s[:k]+A+s[k+1:j]+A+s[j+1:]

Önceki sürüm:

Giriş, '.' İle tek bir dizedir. ve sırasıyla su ve toprağı temsil eden '#'. 'X' çıktıdaki kulübeleri temsil eder.

def f(s):
 w=s.find('\n')+1;d=u={(k,k):0for k,c in enumerate(s)if'#'==c}
 while u:d.update(u);u={(k,j):d[(k,i)]+1 for k,i in d for j in{i+1,i+w,i-1,i-w}if'#'==s[j]and(k,j)not in d}
 k,j=sorted(max(d,key=d.get))
 return s[:k]+'X'+s[k+1:j]+'X'+s[j+1:]

Açıklama:

Temel olarak, aynı anda her olası başlangıç ​​noktasından önce bir genişlik araması yapıyor. Yolun başlangıcı ve bitişi tarafından anahtarlanan yol uzunluklarının sözlüğünü, d, tutun; örneğin, d [(k, i)] k ile i arasındaki mesafedir. Daha sonra sözlükteki d tuşlarını tekrarlayın ve yeni bir sözlük oluşturun, u, bitiş noktası 1 birimini N, S, E, W, örneğin u [(k, i + 1)] = d [(k, i)] + 1. Zaten d'de olan yolları eklemeyin. U boş değilse, d'ye daha uzun yeni yollar ekleyin ve tekrarlayın. U boş olduğunda, başka yol yapılamaz demektir. Şimdi d olası tüm yolları ve uzunluklarını içerir. Bu sadece anahtarı en uzun yolla elde etme meselesi.

Daha az golf edilmiş, yorumlanmış sürüm:

def f(s):
  w=s.find('\n')+1                    # width of a row, or a move N or S

  d = {}                              # dictionary of all the paths.
                                      # The key is a tuple (k,j) and the
                                      # value is the distance from k to j.
  for k,c in enumerate(s):            # Initialize. Distance from k to k is 0
    if'#'==c:                         # Only do land.
      d[(k,k)] = 0

  u = d                               # dictionary of new paths. initialize it to d
                                      # so loop is entered. first d.update is
                                      # basically a NOP

  while u:                            # while there are new paths
    d.update(u)                       # add the new paths to the dict of old paths
    u={}                              #
    for k,i in d:                     # iterate over the known paths. k is the start, i is the end
      for j in{i+1,i+w,i-1,i-w}:      # iterate over squares 1 move to the E,S,W,N from i
        if'#'==s[j]and(k,j)not in d:  # if it's still land, and the path (k,j) isn't already in d,
          u[(k,j)] = d[(k,i)]+1       # then add the new path to u

  k,j=sorted(max(d,key=d.get))        # find the longest path

  return s[:k]+'X'+s[k+1:j]+'X'+s[j+1:]  # X marks the endpoints.

3

C #, 387 bayt

Haydi başlayalım...

using C=System.Console;class P{static void Main(){string D="",L;int W=0,H=0,z,n,q,h,b=0,c,a,i=0,j=0;for(;(L=C.ReadLine())!=null;H+=W=L.Length)D+=L+="\n";for(z=H;z-->0;){int[]S=new int[H],Q=new int[H*8];for(Q[h=q=0]=z;q<=h;)if((c=S[n=Q[q++]]-1)<0&D[S[n]=n]==35)for(a=4;a-->0;b=c<b?c+(i=z)*(j=n)*0:b)S[Q[++h]=new[]{1,-1,W,-W}[a]+n]=S[Q[h]]<1?c:1;}for(;++z<H;)C.Write(z==i|z==j?'X':D[z]);}}

Çevrimiçi Deneyin

Komple program, STDIN okur, STDOUT yazar. Her hücrenin üzerinden geçer ve en uzaktaki hücreyi hesaplamak için bir BFS çalıştırır ve her ikisi de kayıttaki en uzak olanı kaydeder. Gerçekten hiçbir şey ve sinir bozucu küçük ben golf bulabilirsiniz.

Biçimlendirilmiş ve yorumlanmış kod:

using C=System.Console;

class P
{
    // \n 10
    // \r 13
    // . 46
    // # 35
    // x 88

    static void Main()
    {
        string D="", // map
            L; // line of input

        int W=0, // width
            H=0, // length
            z, // outer position
            n, // next position to expand
            q, // queue position pointer
            h, // queue head pointer
            b=0, // best
            c, // distance to this cell (negative)
            a, // counter
            i=0, // hermit 1 pos
            j=0; // hermit 2 pos

        for(;(L=C.ReadLine())!=null; // read a line, while we can
                H+=W=L.Length) // record the width, and add to length
            D+=L+="\n"; // add a newline, and add the line to the map

        for(z=H;z-->0;) // for each cell
        {
            int[]S=new int[H], // 'seen' >0 -> seen, else it is the distance we have found to it
                Q=new int[H*8]; // due queue (fewer than H*4 expantions, two ints each)

            // standard BFS
            for(Q[h=q=0] // reset currect 
                =z; // expand z first
                q<=h;)
                if((c=S[n=Q[q++]]-1)<0& // record 'seen', and check we havn't been seen
                    D[S[n]=n]==35) // mark as seen, and check we are a hash #
                    // 'move'
                    for(a=4;a-->0; // for each of the 4 neighbours
                            b=c<b? // if we have beaten the best
                            c+(i=z)*(j=n)*0: // set new best, record hermit positions
                            b)
                        S[Q[++h]=new[]{1,-1,W,-W}[a]+n]= // queue it for expantion
                        S[Q[h]]<1? // not seen? (this is BFS, don't need to check c is less thatn S[l+n]
                        c: // distance
                        1; // mark as seen (means it won't actually be expanded)
        }

        // z = -1
        for(;++z<H;) // for each cell
            C.Write(z==i|z==j?'X':D[z]); // print either the original char, or X if it is a hermit's home
    }
}
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.