Pemerintah memiliki Pasokan Tembok Terbatas

28

pengantar

Para pegolf kode yang berpengetahuan mempersiapkan kami untuk banjir kiamat . Daerah yang berisiko dievakuasi, dan penduduk pindah ke tempat tinggi.

Kami meremehkan banjir (atau mungkin ada bug dalam kode @ user12345). Beberapa daerah dataran tinggi dengan cepat mendekati permukaan laut. Dinding harus didirikan untuk memastikan kelangsungan hidup perkemahan yang sekarang berpenduduk padat. Sayangnya, pemerintah memiliki persediaan tembok yang terbatas.

Masalah

Skenario kiamat kami dijelaskan oleh dua angka pada satu baris, ndan m. Mengikuti garis itu adalah ngaris dengan mnilai per baris, hanya dipisahkan oleh satu spasi. Setiap nilai akan menjadi satu dari empat karakter.

  • xTidak bisa dilewati. Air tidak bisa mengalir di sini. Dinding tidak dapat didirikan di sini.
  • -Tidak stabil. Air dapat mengalir melalui ini di sini. Dinding tidak dapat didirikan di sini.
  • .Stabil. Air bisa mengalir lewat sini. Dinding dapat didirikan di sini.
  • oPerkemahan. Air bisa mengalir lewat sini. Jika ya, semua orang mati. Dinding tidak dapat dibangun di sini.

Air akan mengalir dari semua tepi peta, kecuali jika tepinya tidak bisa dilewati atau dinding dibangun di atas ubin. Tulis program yang dapat menampilkan jumlah dinding minimum yang diperlukan untuk melindungi perkemahan.

Contoh Input

 6 7
 x . . x x x x
 x . . x - - x
 x . x x - - x
 x . o o o - .
 x . o o o - .
 x x x x x x x

Contoh Output

3

Asumsi

  • Air hanya mengalir secara orthogonal
  • Perkemahan hanya ada sebagai satu blok yang berdekatan secara ortonagon per skenario
  • Sebuah solusi akan selalu ada (walaupun mungkin membutuhkan banyak dinding)
  • Perkemahan tidak dapat ditemukan di tepi, karena skenario kemudian tidak memiliki solusi
  • 2 n<<16
  • 2 m<<16
  • Masukan dapat diberikan dari stdin, baca dari "city.txt", atau diterima sebagai argumen tunggal

Kode terpendek menang!

Rainbolt
sumber
2
Apakah dapat diterima bahwa program itu benar, namun membutuhkan waktu lebih lama daripada alam semesta yang diketahui ada untuk memberikan solusi bagi contoh masalah tertentu?
Claudiu
@Claudiu Saya agak baru di Code Golf. Persyaratan saya gagal menentukan batas waktu, jadi tidak ada. Beban jatuh ke jawaban untuk membuktikan bahwa solusi itu benar untuk semua contoh masalah. Jika Anda memiliki solusi yang memecahkan beberapa (tapi tidak semua) contoh dengan cara yang pintar / keren, saya masih mendorong Anda untuk mempostingnya hanya untuk bersenang-senang.
Rainbolt
2
Golf kode biasanya tidak memerlukan batasan waktu.
Hosch250
Keren! T lain: apakah input harus seperti yang Anda tentukan atau dapatkah kami memasukkannya ke formulir lain?
Claudiu
@Claudiu Saya tidak bisa menerima apa pun di luar persyaratan. Namun, Anda dapat menyarankan edit untuk persyaratan menggunakan tombol edit . Melihat belum ada jawaban, saya mungkin akan segera menerima hasil edit.
Rainbolt

Jawaban:

10

Mathematica, 257 253 karakter

d="city.txt"~Import~"Table";g=EdgeAdd[#,∞<->Tr@#&/@Position[VertexDegree@#,2|3]]&@GridGraph@d[[1,{2,1}]];{o,x,s}=Tr/@Position[Join@@d[[2;;]],#]&/@{"o","x","."};Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]

Input dibaca dari "city.txt".

Penjelasan:

Mathematica memiliki banyak fungsi untuk menangani grafik.

Pertama, saya membaca data dari "city.txt".

d="city.txt"~Import~"Table";

Lalu saya membangun grafik kotak dengan 'm' * 'n' simpul ( GridGraph@d[[1,{2,1}]]), dan menambahkannya "titik di infinity" yang terhubung ke setiap titik di "tepi" grafik. Vertex ini adalah tempat air mengalir.

g=EdgeAdd[#,∞<->Tr@#&/@Position[VertexDegree@#,2|3]]&@GridGraph@d[[1,{2,1}]];

Dan o, xdan smenunjukkan posisi "o", "x" dan "." masing-masing.

{o,x,s}=Tr/@Position[Join@@d[[2;;]],#]&/@{"o","x","."};

Kemudian untuk setiap bagian wdari s(himpunan bagian diurutkan menurut panjang), saya menghapus simpul di xdan wdari g( VertexDelete[g,x⋃w]), dan menemukan panjang jalur terpendek dari "titik di infinity" untuk perkemahan o. Jika panjangnya tak terbatas, maka perkemahan akan aman. Jadi panjang yang pertama wadalah jumlah minimum dinding yang dibutuhkan untuk melindungi perkemahan.

Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]
alephalpha
sumber
Bagus! Saya pikir saya akan didekati oleh pendekatan berbeda dalam bahasa yang berbeda.
Claudiu
1
Upvoting tapi saya akan melakukannya dengan lebih bangga jika Anda akan menjelaskan kode Anda untuk kita semua.
Michael Stern
Adakah yang bisa memastikan bahwa jawaban ini benar atau memberikan intepreter online untuk "Mathematica"? Kesulitan menemukan satu.
Rainbolt
1
@Rusher Saya sudah memverifikasi itu, dan itu solid. Tidak ada juru bahasa online untuk MM, tetapi ada format dokumen CDF yang dapat diunduh dan saya dan beberapa orang lain telah mulai bereksperimen untuk berbagi solusi. Anda juga bisa mendapatkan Mathematica secara gratis dengan komputer Raspberry Pi ARM, dengan peringatan bahwa Anda dibatasi oleh kekuatan komputasi kotak itu. FWIW, kami pengguna MM melakukan yang terbaik untuk menjaga satu sama lain jujur ​​dan kami sedang berupaya membuat kiriman kami lebih mudah diakses (masalah juga dihadapi oleh bahasa Matlab, Maple, MS yang tidak bekerja pada Mono, dll.)
Jonathan Van Matre
4

C, 827 799 522

Golf:

#define N for(
#define F(W,X,Y,Z) N i= W;i X Y;i Z)
#define C(A,B,C) if(c[A][B]==C)
#define S(W,X,Y,Z,A,B) p=1;F(W,X,Y,Z)C(A,B,120)p=0;if(p){F(W,X,Y,Z){C(A,B,46){c[A][B]='x';z++;Q();break;}}}else{F(W,X,Y,Z){C(A,B,120)break;else c[A][B]='o';}}
p,m,z,w,h,o,i,u,l,x,y;char c[16][16];Q(){N u=0;u<h;u++)N l=0;l<w;l++)if(c[u][l]=='o'){x=u;y=l;S(x,>,m,--,i,y)S(y,>,m,--,x,i)S(y,<,w,++,x,i)S(x,<,h,++,i,y)}}main(int a, char **v){h=atoi(v[1]);w=atoi(v[2]);N m=-1;o<h;o++)N i=0;i<w;i++)scanf("%c",&c[o][i]);Q();printf("%d",z);}

Input diberikan dengan tinggi dan dengan sebagai argumen baris perintah, dan kemudian grid dibaca sebagai string tunggal pada stdin seperti: di ./a.out 6 7 < inputmana input berada dalam bentuk ini (kiri ke kanan, atas ke bawah):

x..xxxxx..x - xx.xx - xx.ooo-.x.ooo-.xxxxxxx

"Dapat dibaca":

#define F(W,X,Y,Z) for(i= W;i X Y;i Z)
#define C(A,B,C) if(c[A][B]==C)
#define S(W,X,Y,Z,A,B) p=1;F(W,X,Y,Z)C(A,B,120)p=0;if(p){F(W,X,Y,Z){C(A,B,46){c[A][B]='x';z++;Q();break;}}}else{F(W,X,Y,Z){C(A,B,120)break;else c[A][B]='o';}}

/*Example of an expanded "S" macro:
p=1;
for(i=x;i>m;i--) if(c[i][y]==120) p=0;
if(p)
{
    for(i=x;i>m;i--)
    {
        if(c[i][y]==46)
        {
            c[i][y]='x';
            z++;
            Q();
            break;
        }
    }
}
else
{
    for(i= x;i > m;i --)
    {
        if(c[i][y]==120) break;
        else c[i][y]='o';
    }
}
*/

p,m,z,w,h,o,i,u,l,x,y;
char c[16][16];
Q(){
    for(u=0;u<h;u++)
        for(l=0;l<w;l++)
            if(c[u][l]=='o')
            {
        x=u;y=l;
        S(x,>,m,--,i,y)
        S(y,>,m,--,x,i)
        S(y,<,w,++,x,i)
        S(x,<,h,++,i,y)
            }
}

main(int a, char **v)
{
    h=atoi(v[1]);
    w=atoi(v[2]);
    for(m=-1;o<h;o++)
        for(i=0;i<w;i++)
            scanf("%c",&c[o][i]);
    P();
    Q();
    printf("%d\n",z);
    P();
}

//Omitted in golfed version, prints the map.
P()
{
    for(o=0;o<h;o++)
    {
        for (i=0;i<w;i++) printf("%c",c[o][i]);
        printf("\n");
    }   
}

Tidak ada yang sesingkat solusi oleh @Claudiu, tetapi berjalan sangat cepat. Alih-alih mengisi banjir dari tepi, ia menemukan perkemahan dan bekerja keluar dari token 'o'.

  • Jika menemukan tanah yang tidak stabil di sebelah perkemahan, itu akan memperluas perkemahan ke atasnya.
  • Jika ada perkemahan di grid tidak memiliki setidaknya satu dinding di setiap arah, itu bergerak ke arah itu sampai dapat membangun tembok.
  • Setelah setiap bagian dinding baru ditempatkan, itu berulang untuk menemukan bagian dinding berikutnya untuk ditempatkan.

Contoh penempatan dinding:

x..xxxx                           x..xxxx
x..x--x                           x..xoox
x.xx--x                           x3xxoox
x.ooo-.  <-- results in this -->  xooooo1
x.ooo-.                           xooooo2
xxxxxxx                           xxxxxxx
Komintern
sumber
Oh, pendekatan yang menarik! Apakah selalu memberikan jawaban terpendek? mis. jawaban apa yang diberikannya untuk peta ini ? Itu harus 3 (ditandai dengan dinding baru @). Saya mencoba menjalankan kode Anda sendiri tetapi tampaknya tidak berhasil
Claudiu
Ups, sepertinya golf dan alkohol tidak tercampur dengan baik ... Saya bermain golf dalam perilaku yang tidak terdefinisi. Harus diperbaiki sekarang bersama dengan 277 karakter yang tidak perlu.
Comintern
2
@Claudiu - Lihat komentar saya di atas, hasil untuk peta yang Anda posting ada di pastebin.com/r9fv7tC5 . Ini harus selalu memberikan jawaban terpendek, tetapi saya hanya mengujinya dengan 10 atau 15 peta yang saya pikir mungkin menyajikan kasus sudut. Saya ingin tahu apakah ada yang bisa mengidentifikasi peta yang gagal.
Comintern
4

Python, 553 525 512 449 414 404 387 368 karakter (+4? Untuk doa)

Saya terlalu senang bermain golf ini. Ini 82 byte lebih besar jika Anda mencoba mengompres! Nah, itu ukuran kekompakan dan kurangnya pengulangan.

R=range;import itertools as I
f=map(str.split,open('city.txt'))[1:]
S=[]
def D(q):
 q=set(q)
 def C(*a):
    r,c=a
    try:p=(f[r][c],'x')[a in q]
    except:p='x'
    q.add(a)
    if'.'==p:S[:0]=[a]
    return p<'/'and C(r+1,c)|C(r-1,c)|C(r,c+1)|C(r,c-1)or'o'==p
 if sum(C(j,0)|C(j,-1)|C(0,j)|C(-1,j)for j in R(16))<1:print n;B
D(S);Z=S[:]
for n in R(len(Z)):map(D,I.combinations(Z,n))

Level indentasi adalah spasi, tab.

Pemakaian :

Baca dari city.txt:

6 7
x . . x x x x
x . . x - - x
x . x x - - x
x . o o o - .
x . o o o - .
x x x x x x x

Ajukan sebagai berikut:

$ python floodfill_golf.py 2>X
3

Itu 2>X adalah untuk menyembunyikan stderr sejak keluar program dengan menaikkan pengecualian. Jika ini dianggap tidak adil, jangan ragu untuk menambahkan 4 karakter untuk doa.

Penjelasan :

Kekuatan kasar sederhana. Cmelakukan pengisian banjir dan mengembalikan true jika mencapai perkemahan. Tidak ada bantalan tambahan karena terlalu banyak ruang untuk memasang bantalan dengan benar. D, diberi satu set dinding untuk diisi, panggilan Cdari setiap titik di tepi sedemikian rupa sehingga Cmenyumbang dinding itu, dan mencetak panjang dan keluar jika tidak ada yang mencapai perkemahan. Daftar dinding juga digunakan untuk melacak banjir, jadi tidak perlu menyalin papan! Trickily, Cjuga menambahkan setiap tempat kosong yang ditemukan ke daftar, Ssehingga fungsi Dtersebut juga digunakan untuk membangun pertama daftar tempat kosong. Untuk alasan ini, saya menggunakan sumalih-alih any, untuk memastikan semua data .dikumpulkan pada run-through pertama.

Saya memohon Dsekali, lalu menyalin daftar tempat kosong ke Zkarena Sakan terus ditambahkan (tidak efisien, tetapi lebih murah pada jumlah karakter). Lalu saya gunakanitertools.combinations untuk memilih masing-masing kombo tempat kosong, dari 0 tempat ke atas. Saya menjalankan setiap kombo melalui Ddan mencetak panjang yang pertama yang berhasil, menimbulkan pengecualian untuk keluar dari program. Jika tidak ada jawaban yang ditemukan maka tidak ada yang dicetak.

Perhatikan bahwa saat ini, program tidak berfungsi jika tidak diperlukan dinding. Ini akan menjadi +3 karakter untuk menangani kasus ini; tidak yakin apakah itu perlu.

Perhatikan juga bahwa ini adalah O(2^n)algoritma, di mana njumlah tempat kosong. Jadi, untuk papan berukuran 15x15 yang benar-benar kosong dengan satu perkemahan di tengahnya, ini akan membutuhkan 2^(15*15-1)= 2.6959947e+67iterasi untuk diselesaikan, yang akan menjadi waktu yang sangat lama!

Claudiu
sumber
1

Groovy: 841 805 754

i=new File("city.txt").getText()
x=i[2] as int
y=i[0] as int
m=i[4..i.length()-1].replaceAll('\n','').toList()
print r(m,0)
def r(m,n){if(f(m))return n;c=2e9;g(m).each{p=r(it,n+1);if(p<c)c=p;};return c;}
def f(m){u=[];u.addAll(m);for(i in 0..(x*y)){for(l in 0..m.size()-1){n(l,u);s(l,u);e(l,u);w(l,u);}};m.count('o')==u.count('o')}
def n(i,m){q=i-x;if((((q>=0)&(m[q]=='!'))|(q<0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def s(i,m){q=i+x;if((((q>=0)&(m[q]=='!'))|(q<0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def e(i,m){q=i+1;if((((q%x!=0)&(m[q]=='!'))|(q%x==0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def w(i,m){q=i-1;if((((i%x!=0)&(m[q]=='!'))|(i%x==0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def g(m){v=[];m.eachWithIndex{t,i->if(t=='.'){n=[];n.addAll(m);n[i]='W';v<<n}};return v}

Tidak Terkumpul:

def i = new File("city.txt").getText()
x=i[2].toInteger()
y=i[0].toInteger()
def m=i[4..i.length()-1].replaceAll('\n','').toList()
println r(m, 0)

def r(m, n){
    if(f(m)) return n
    def c = Integer.MAX_VALUE

    getAllMoves(m).each{ it -> 
        def r = r(it, n+1)
        if(r < c) c = r
    }
    return c;
}

def f(m){
    def t = []
    t.addAll(m)
    for(i in 0..(x*y)){
        for(l in 0..m.size()-1){
            n(l,t);s(l,t);e(l,t);w(l,t);
        }
    }
    m.count('o')==t.count('o')
}

def n(i,m){
    def t = i-x;
    if( ( ( (t >= 0) && (m[t]=='!') ) || (t < 0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def s(i,m){
    def t = i+x;
    if( ( ( (t >= 0) && (m[t]=='!') ) || (t < 0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def e(i,m){
    def t = i+1;
    if( ( ( (t%x!=0) && (m[t]=='!') ) || (t%x==0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    } 
}

def w(i,m){
    def t = i-1;
    if( ( ( (i%x!=0) && (m[t]=='!') ) || (i%x==0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def getAllMoves(m){
    def moves = []
    m.eachWithIndex { t, i ->
        if(t=='.'){
            def newList = []
            newList.addAll(m)
            newList[i]='W'
            moves << newList
        }
    }
    return moves
}

Banyak lagi golf yang akan datang ...

Mengembalikan 2E9 jika tidak ada solusi.

md_rasler
sumber
0

Dyalog APL , 91 byte

⊃∊{1∊a[⍸×{(×d)∧s 3∨/3∨⌿⍵}⍣≡4=d←0@⍵⊢a]:⍬⋄≢⍵}¨c[⍋≢¨c←(,⍳2⊣¨b)/¨⊂b←⍸2=a←(s←(4,4,⍨⍉)⍣2)'xo.'⍳⎕]

mengasumsikan ⎕IO=0, menggunakan fitur dari v16.0 ( @dan ), waktu yang berjalan eksponensial dalam jumlah .-s

input dievaluasi, harus menjadi matriks karakter

'xo.'⍳ ganti xdengan 0, odengan 1, .dengan 2, dan yang lainnya dengan 3

s←(4,4,⍨⍉)⍣2 fungsi yang mengelilingi matriks dengan 4s

a← menetapkan matriks numerik yang dikelilingi dengan 4s ke sebuah variabel a

b←⍸2= badalah daftar pasangan coord di mana 2s (yaitu .-s) berada

(,⍳2⊣¨b)/¨⊂b menghasilkan semua kombinasi elemen b

c[⍋≢¨c←...] urutkan berdasarkan ukuran

{... :⍬⋄≢⍵}¨ untuk setiap kombinasi, periksa sesuatu dan kembalikan baik panjangnya atau daftar kosong

⊃∊ hasil non-kosong pertama

d←0@⍵⊢a dadalah adengan beberapa elemen diganti dengan 0

4= buat boolean matrix - di mana 4s? yaitu perbatasan yang kami tambahkan

{...}⍣≡ terus menerapkan fungsi {}sampai hasilnya stabil

3∨/3∨⌿⍵ "Boolean atau" setiap elemen dengan tetangganya

s hasilnya akan lebih kecil, jadi mari kita buat kembali perbatasan

(×d)∧ menerapkan elemen non-nol d(non-dinding) sebagai topeng boolean

a[⍸× ...] apa yang asesuai dengan 1 dalam matriks boolean kami?

1∊ apakah ada 1, yaitu o, perkemahan?

ngn
sumber