Buzdağı üzerine telli bilim adamı mühürler


17

Giriş

Kuzey Kutup Dairesi'ndeki bir buzdağı üzerinde bir fok ailesi vardır. Buzdağının üzerinde, mühürlerin yardım istemek için kullanabileceği bir radyo vericisi vardır. Ancak, yalnızca baba mührü radyo vericisinin nasıl çalıştırılacağını bilir. Ve daha da kötüsü, buz yılın bu zamanında çok kaygandır, bu yüzden mühürler başka bir mührü vuruncaya veya buzdağının kenarından kayıncaya kadar kontrolsüz bir şekilde kayacak ve baba mührünün radyo vericisine ulaşmasını zorlaştıracaktır. Neyse ki, mühürlerden biri bir bilgisayar bilimcisi, bu yüzden baba mührünün radyo vericisine nasıl manevra yapılacağını anlamak için bir program yazmaya karar veriyor. Bir program yazmak için buz üzerinde çok yer olmadığından, programı mümkün olduğunca az bayt kullanmaya karar verir.

Giriş Açıklaması

Mühürün programı STDIN, komut satırı bağımsız değişkenleri veya kullanıcı giriş işlevlerinden (örneğin raw_input()) girdi alır . Bir değişkende önceden başlatılamaz (örn. "Bu program, bir değişkende girişi beklerx ").

Girişin ilk satırı, formdaki virgülle ayrılmış iki tamsayıdan oluşur

A,B

Bunu her biri karakterlerden Boluşan satırlar izler A. Her satır yalnızca aşağıdakilerin dışında karakterler içerebilir:

  • .: Soğuk, soğuk, okyanus. Harita her zaman buna bir sınır olarak sahip olacak.
  • #: Buzdağının bir parçası.
  • a... z: Buzdağındaki baba mühürü olmayan bir mühür.
  • D: Buzdağındaki baba foku.
  • *: Radyo vericisi.

(Baba mührünün her zaman büyük harfle not edildiğini unutmayın D. Küçük harf dnormal bir mühürdür.)

Çıktı Açıklaması

Mühürlerin nasıl hareket edebileceğine ilişkin aşağıdaki kurallara göre, baba mührünü radyo vericisine almak için nasıl hareket etmeleri gerektiğine dair mühürlerin bir listesini verin.

  1. Kural: Tüm mühürler yukarı ( U), aşağı ( D), sola ( L) ve sağa ( R) hareket edebilir. Çapraz olarak kaymazlar.
  2. Kural: Hareket halinde, bir mühür başka bir mühürle çarpışana veya denize düşene kadar aynı yönde hareket etmeye devam edecektir.
    1. Bir mühür başka bir mühürle çarpışırsa, hareket etmeyi durduracaktır. Çarpıştığı mühür olmaz taşıyın.
    2. Bir mühür denize düşerse, boğulur ve haritadan kaybolur. Yani, diğer mühürler için bir çarpıştırıcı gibi davranmaz ve tekrar hareket ettirilemez.
  3. Kural: İki mühür aynı anda hareket edemez, diğeri hareket ederken bir mühür de hareket ettirilemez. Bir sonraki conta yalnızca önceki conta hareket etmeyi kestikten sonra hareket ettirilebilir.
  4. Kural: Bir mührün birden çok kez taşınması veya boğulan contaların sayısı konusunda herhangi bir kısıtlama yoktur.
  5. Kural: Doğru bir çözüm , radyo vericisinde baba mühür ucuna sahip olacaktır . Baba mühür kayarken vericiyi geçemez .

Çıktı, her biri formunda olan birkaç satırdan oluşacaktır

A,B

Burada A(hareket mühürdür Dbaba mühür, a... zdiğerleri için), ve B(ya da bir sızdırmazlık hareket yönü U, D, Lya da R). En kısa rotayı bulmanız gerekmediğini unutmayın .Baba mührünü hedefe ulaştıran her rota kabul edilebilir bir çıktıdır.

Örnek Girişler ve Çıkışlar

Giriş:

25,5
.........................
.#######################.
.####D#############*k###.
.#######################.
.........................

Çıktı:

D,R

Giriş:

9,7
.........
.a#####b.
.#####d#.
.##l*###.
.###m#p#.
.#D#.#c#.
.........

Çıktı (birçoğu için olası bir çıktı):

m,R
b,L
D,U
D,R
D,D
D,L

Giriş:

26,5
..........................
.###..................###.
.l*##########v#########D#.
.###..................###.
..........................

Çıktı (birçoğu için olası bir çıktı):

v,D
D,L

Başka sorularınız varsa, lütfen yorumlarda sorun.


Tüm girdilerin geçerli bir çözümü olacak mı? Değilse, beklenen çıktı / davranış nedir?
Geobits

@ Geobits Tüm girdilerin geçerli bir çözümü olacaktır. Çözümü olmayan girdiler geçersiz sayılır ve programınız bunlarla her şeyi yapabilir.
pelin

Bir istisna atarak programı sonlandırmaya izin veriliyor mu?
DLosc

2
Baba olmayan bir mühür radyo vericisine çarparsa ne olur? Durur mu yoksa ilerler mi?
Reto Koradi

1
Bu benim çözümümü geçersiz kılar. :(
DLosc

Yanıtlar:


6

Python 3, 520 bayt

R=range
g=[list(input())for i in R(int(input().split(',')[1]))]
f=set(sum(g,[]))-set(".#*")
L=8
def P(p,g):
 if len(p)>L:return
 for s in f:
  c=sum(y.index(s)for y in g if s in y)
  if c<1:continue
  r,=[n for n in R(len(g))if s in g[n]]
  for d in R(4):
   m=p+s+",%s\n"%"LURD"[d];G=[y[:]for y in g];o="#";i,j=I,J=r,c
   while"#"==o:G[i][j]="#";G[I][J]=s;i,j=I,J;I,J=i+d%2*(d-2),j+(~d%-2&d-1);o=G[I][J]
   if"."==o:G[i][j]="#"
   if"D"==s:
    if"."==o:continue
    if"*"==o:print(m);1/0
   P(m,G)
while 1:P("",g);L+=4

İnsanlar isterse daha ayrıntılı bir açıklama yapabilirim, ancak temelde bu yinelemeli derinleşmeyle önce derinlikli bir arama yapar , olası hareketlerin durum alanını . Bir hamle baba mührünün düşmesine neden olursa, derhal reddedilir. Baba vericinin yanında biterse, hareket sırası yazdırılır ve program bir çıkışı zorlamak için sıfıra bölünür.

if G!=g:8 ekstra bayt için ikinci son satırın başına ekleyerek kodu önemli ölçüde daha hızlı çalıştırabilirsiniz - bu gibi bir şey değişmez hareketleri reddederk,L ilk test durumda .

Çalışma zamanı, aynı girişle bile bir çalışmadan diğerine fark edilir şekilde değişir - açıkçası, bir set , sıra dışı bir tür olan . İkinci test vakasını 5 dakika 30 saniyede zamanladım, ancak ilk kez çalıştırdığımda çok uzun görünmüyordu. Yukarıda bahsedilen optimizasyon ile, daha çok 40 saniye gibi.


1
İlginçtir ki Python 2'de her seferinde aynı sırayı vermelidir. Sanırım Python 3'ü, belirli açıklardan kaçınmak için aynı nesneler için her çalıştırmada rastgele karmalar vermek üzere değiştirdiler : "Karma rastgelelaştırma varsayılan olarak etkindir. Karma rastgelelaştırmayı devre dışı bırakmak için PYTHONHASHSEED ortam değişkenini 0 olarak ayarlayın. Ayrıca nesne .__ karma __ () yöntem."
Claudiu

4

JavaScript (ES6) 322 334 323

Edit2 Snippet'e animasyon eklendi

Düzenleme bir mühür üzerinde slayt ve silmenize bile bunu bulmak böylece Hata düzeltme, '*' ilk posiiton hatırlıyorum.

Parametre olarak giriş dizesi ile bir işlev olarak uygulanır (muhtemelen geçersizdir, ancak açıklama beklenir). Pop-up üzerinden çıktı.
JavaScript'te çok satırlı dize girişi ile ilgili sorunprompt onu iyi yönetmemesi.

Algoritma gelince: bir BFS, en uygun çözümü bulmalıdır. Değişken bir oyun durumu kuyruğu l, karakter ızgarasını oluşturan durum gve şimdiye kadarki hareket sırasını tutuyorum s. Ayrıca, kaynı ızgarayı tekrar tekrar keşfetmekten kaçınmak için değişken olarak şimdiye kadar elde edilen bir dizi ızgara vardır.

Ana döngü

  • oyun statüsünü düşürmek
  • tüm olası hareketleri deneyin, her geçerli hareketten sonra durumu enqueque edin (elde edilen ızgara zaten mevcut değilse)
  • çözüm bulunursa döngüden çıkın
F=s=>{
  o=~s.match(/\d+/),g=[...z=s.replace(/.*/,'')];
  for(l=[[g,'']],k=[];[g,s]=l.shift(),!g.some((c,p)=>
      c>'A'&&[-1,1,o,-o].some((d,j)=>{
        t=s+' '+[c,'LRUD'[j]];
        for(q=p;(u=g[q+d])<'.';)q+=d;
        return(c<'a'&z[q]=='*')||
        c>'D'|u>'.'&&!(
          f=[...g],u=='.'?0:f[q]=c,f[p]='#',
          k[h=f.map(v=>v>'D'?0:v)]||(k[h]=l.push([f,t]))
        )
      })
    ););
  alert(t)
}

FireFox'ta test etmek için Snippet'i çalıştırın


1

C ++, 628 bayt

Bu çok kısa olmadı:

#include <set>
#include <iostream>
using namespace std;struct R{string b,m;bool operator<(R r)const{return b<r.b;}};int w,h,t,j,k,z=1;char c,f;set<R> p,q;int m(R r,int x,int d,char a){for(j=x,c=r.b[x];(f=r.b[j+=d])==35;);if(c-68||f-46){r.b[x]=35;if(f-46)r.b[j-d]=c;r.m+=c;r.m+=44;r.m+=a;r.m+=10;if(c==68&j-d==t){cout<<r.m;z=0;}if(p.count(r)+q.count(r)==0){q.insert(r);}}}int main(){cin>>w>>c>>h>>c;R r;string l;for(;k++<h;){getline(cin,l);r.b+=l;}t=r.b.find(42);r.b[t]=35;q.insert(r);for(;z;){r=*q.begin();q.erase(q.begin());p.insert(r);for(k=0;z&&k<w*h;++k){if(r.b[k]>64){m(r,k,-1,76);m(r,k,1,82);m(r,k,-w,85);m(r,k,w,68);}}}}

C ++ 'ı seçtim çünkü veri yapılarını ( set, string) kullanmak istedim , ama doğal olarak oldukça ayrıntılı. Çözüm, çalışma zamanı için optimize edilmemiş olsa da, MacBook Pro'da test 2'yi 2 saniyeden biraz fazla bir sürede çözerek performansta oldukça iyi sonuç verir.

Boşluğu ve diğer bazı uzunlukları azaltmaya başlamadan önce kodlayın:

#include <set>
#include <iostream>

using namespace std;

struct R {
    string b, m;
    bool operator<(R r) const {return b < r.b; }
};

int w, h, t;
set<R> p, q;
bool z = true;

void m(R r, int k, int d, char a) {
    int j = k;
    char s = r.b[k], f;
    for (; (f = r.b[j += d]) == 35;);
    if (s - 68 || f - 46) {
        r.b[k] = 35;
        if (f - 46) {
            r.b[j - d] = s;
        }
        r.m += s;
        r.m += 44;
        r.m += a;
        r.m += 10;
        if (s == 68 && j - d == t) {
            cout << r.m;
            z = false;
        }
        if (p.count(r) + q.count(r) == 0) {
            q.insert(r);
        }
    }
}

int main() {
    char c;
    cin >> w >> c >> h >> c;
    string b, l;
    int k;
    for (k = 0; k < h; ++k) {
        getline(cin, l);
        b += l;
    }

    t = b.find(42);
    b[t] = 35;

    R r;
    r.b = b;
    q.insert(r);

    for ( ; z; ) {
        r = *q.begin();
        q.erase(q.begin());
        p.insert(r);

        for (k = 0; z && k < w * h; ++k) {
            c = r.b[k];
            if (c > 64) {
                m(r, k, -1, 76);
                m(r, k, 1, 82);
                m(r, k, -w, 85);
                m(r, k, w, 68);
            }
        }
    }

    return 0;
}

Algoritmanın arkasındaki ana fikir, iki setin sürdürülmesidir:

  • q işlenmeyi bekleyen yapılandırma kümesidir.
  • p işlenen yapılandırma kümesidir.

Algoritma, başlangıçtaki yapılandırma ile başlar q. Her adımda, olası tüm conta hareketlerinden bir konfigürasyon açılır q, buna eklenir p, ortaya çıkan yeni konfigürasyonlar eklenir q.

Test sürüşü:

bash-3.2$ ./a.out <test1
D,R
bash-3.2$ time ./a.out <test2
p,U
c,U
p,R
c,L
m,L
b,L
a,L
D,U
b,L
D,R
D,D
D,L

real    0m2.267s
user    0m2.262s
sys 0m0.003s
bash-3.2$ ./a.out <test3
v,U
D,L
bash-3.2$

'Q' için ayarlanmak yerine bir kuyruk kullanarak daha kısa sürede daha kısa çözümler bulabilirsiniz (test 2 için çözümüm 6 adımdır).
edc65

@ edc65 Evet, başlangıçta oradaki hamle sayısına şaşırdım. Bunun geçerli bir çözüm olduğunu doğrulamak için yürüdüm. Bunun için bir FIFO kullanmak qkesinlikle daha iyi olurdu. Bir set kullanmamın nedeni, aynı girişi birden çok kez girmek istemememdi. Ama sonucu gördükten sonra ikinci düşünceler almaya başladım.
Reto Koradi

Performans açısından, tekrarları önlemek için bir sıra VE bir küme kullanmalısınız. Ancak sete, her bir bebek mührü değiştirilebilir olduğu için ızgaranın değiştirilmiş bir versiyonunu koyun.
edc65
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.