Adalar (ve nehir) haritası


20

Giriş

Yüzyıllar boyunca, hiç haritalandırılmamış belirli bir nehir vardı. Haritacılar Birliği, nehrin haritasını çıkarmak istiyor, ancak asla başaramadılar - bir sebepten dolayı, nehri haritalamak için gönderdikleri tüm haritacılar bölgedeki vahşi hayvanlar tarafından yenildi. Farklı bir yaklaşım gereklidir.

Giriş Açıklaması

Alan, uzunluk mve genişlikteki dikdörtgen bir hücre ızgarasıdır n. Sol 0,0alttaki hücre ve sağ üstteki hücre olurdu m-1,n-1. mve ngirişte bir demet olarak sağlanır m,n.

Uzun mesafeli coğrafi sondaj teknikleri kullanılarak, adaların nehir etrafındaki yeri tespit edilmiştir. Adaların büyüklüğü (yani adanın kaç hücre kapladığı) da tanımlanmıştır, ancak şekil tanımlanmamıştır. Biz demet içinde bu bilgileri temin adanın boyutudur ve ve x ve bu adanın belirli bir hücrenin y konumları vardır. Girişteki her bir grup boşlukla ayrılmıştır, bu yüzden örnek bir giriş aşağıdadır:s,x,ysxy

7,7 2,0,0 2,3,1 2,6,1 2,4,3 2,2,4 8,0,6 1,2,6 3,4,6

Daha net açıklamak gerekirse, grafikteki girdiler şunlardır:

 y 6|8 1 3
   5|
   4|  2
   3|    2
   2|
   1|   2  2
   0|2  
     =======
     0123456
     x

Çıktı Açıklaması

Alanın bölümlerini temsil etmek için ASCII karakterlerini kullanarak bir harita çıktısı alın. Her hücre ya #(kara) ya da .(su) olacaktır. Harita şu kurallara uymalıdır:

  1. Tanım. Bir ada, tamamen nehir hücreleri ve / veya bölgenin sınırı ile sınırlanan ortogon olarak bitişik bir kara hücreleri grubudur.
  2. Tanım. Bir nehir, tamamen kara hücreleri ve / veya bölgenin sınırı ile sınırlanan ve "göller" (2x2 alan su hücresi) içermeyen , dikey olarak bitişik bir su hücreleri grubudur .
  3. Kural . Harita tam olarak bir nehir içerecektir.
  4. Kural . Girişteki her numaralı hücre, tam olarak shücreleri içeren bir adanın parçası olmalıdır .
  5. Kural . Haritadaki her ada, girişteki numaralandırılmış hücrelerden birini içermelidir.
  6. Kural . Her girdi için tek bir benzersiz harita vardır.

Örnek girişin çıktısı:

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

İşte başka bir girdi ve çıktı.

Giriş:

5,5 3,0,1 1,4,1 2,0,4 2,2,4 2,4,4

Çıktı:

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

3
Not: Bu bir Nurikabe çözücü ile aynı soru .
pelin

1
Herhangi bir uygun formatta girdi alabilir miyiz, yoksa sorudakine bağlı kalmalı mıyız?
Outgolfer Erik

1
Bu aynı zamanda 2012 Dyalog yarışmasında
ngn

@ngn Ne zamandan beri "bir şifreleme karması yayınla" ... her zamanki gibi? (ancak bir meydan okuma açıkça izin verdiğinde izin verilir)
user202729

1
İşte puzzle-nurikabe.com için bir yer imi - mevcut bulmacayı bu meydan okuma için geçerli bir girişe dönüştürür ve tahtanın hemen altında kırmızı renkte gösterir:javascript:(_=>{var t=Game.nurikabe().task,m=t.length,n=t[0].length,s=[m,n];for(var i=0;i<m;i++)for(var j=0;j<n;j++)if(t[i][j]>=0)s+=' '+[t[i][j],i,j];puzzleContainerDiv.insertAdjacentHTML('beforeend','<hr><tt style=color:red>'+s+'</tt><hr>')})();void(0)
ngn

Yanıtlar:


10

C + PicoSAT , 2345 995 952 bayt

#include<picosat.h>
#define f(i,a)for(i=a;i;i--)
#define g(a)picosat_add(E,a)
#define b calloc(z+1,sizeof z)
#define e(a,q)if(a)A[q]^A[p]?l[q]++||(j[++k]=q):s[q]||(i[q]=p,u(q));
z,F,v,k,n,h,p,q,r,C,*x,*A,*i,*l,*s,*j,*m;u(p){s[m[++n]=p]=1;e(p%F-1,p-1)e(p%F,p+1)e(p>F,p-F)e(p<=F*v-F,p+F)}t(){f(q,k)l[j[q]]=0;f(q,n)s[m[q]]=0;k=n=0;i[p]=-1;u(p);}main(){void*E=picosat_init();if(scanf("%d,%d",&F,&v)-2)abort();z=F*v;for(x=b;scanf("%d,%d,%d",&r,&p,&q)==3;g(p),g(0))x[p=F-p+q*F]=r;f(p,F*v-F)if(p%F)g(p),g(p+1),g(p+F),g(p+F+1),g(0);for(A=b,i=b,l=b,s=b,j=b,m=b;!C;){picosat_sat(E,C=h=-1);f(p,F*v)A[p]=picosat_deref(E,p)>0,i[p]=0;f(p,F*v)if(x[p])if(i[q=p]){for(g(-q);i[q]+1;)q=i[q],g(-q);g(C=0);}else if(t(),r=n-x[p]){f(q,r<0?k:n)g(r<0?j[q]:-m[q]);g(C=0);}f(p,F*v)if(!i[p])if(t(),A[p]){g(-++z);f(q,k)g(j[q]);g(C=0);f(q,n)g(-m[q]),g(z),g(0);}else{C&=h++;f(q,k)g(-j[q]);g(++z);g(++z);g(0);f(q,F*v)g(s[q]-z),g(q),g(0);}}f(p,F*v)putchar(A[p]?35:46),p%F-1||puts("");}

Çevrimiçi deneyin!

(Uyarı: Bu TIO bağlantısı, PicoSAT 965'in küçültülmüş bir kopyasını içeren 30 kilobaytlık bir URL'dir, bu nedenle bazı tarayıcılara yükleyemeyebilirsiniz, ancak en azından Firefox ve Chrome'a ​​yüklenir.)

Nasıl çalışır

SAT çözücüyü her hücre (toprak veya su) için bir değişkenle ve yalnızca aşağıdaki kısıtlamalarla başlatırız:

  1. Her numaralı hücre karadır.
  2. Her 2 × 2 dikdörtgenin en az bir arazisi vardır.

Kısıtlamaların geri kalanının doğrudan SAT'a kodlanması zordur, bu nedenle bir model almak için çözücüyü çalıştırırız, bu modelin bağlı bölgelerini bulmak için önce derinlemesine aramalar gerçekleştiririz ve aşağıdaki gibi ek kısıtlamalar ekleriz:

  1. Çok büyük bir kara bölgesindeki her numaralı hücre için, o bölgedeki mevcut kara hücreleri arasında en az bir su hücresi olması gerektiğine dair bir kısıtlama ekleyin.
  2. Çok küçük bir kara bölgesindeki her numaralı hücre için, o bölgeyi çevreleyen mevcut su hücreleri arasında en az bir kara hücresi olması gerektiğine dair bir kısıtlama ekleyin.
  3. Başka bir numaralı hücreyle aynı arazi bölgesindeki her numaralı hücre için, aralarındaki geçerli kara hücrelerinin yolu boyunca en az bir su hücresi olması gerektiği konusunda bir kısıtlama ekleyin. ).
  4. Numaralı hücre içermeyen her kara bölgesi için,
    • mevcut kara hücrelerinin tümü su olmalı veya
    • o bölgeyi çevreleyen mevcut su hücrelerinden en az biri kara olmalıdır.
  5. Her su bölgesi için,
    • mevcut su hücrelerinin tümü kara olmalı veya
    • mevcut su hücreleri dışındaki her hücre kara olmalı veya
    • o bölgeyi çevreleyen mevcut kara hücrelerinden en az biri su olmalıdır.

PicoSAT kütüphanesinin artan arayüzünden yararlanarak, çözücü tarafından önceki tüm çıkarımları koruyarak, eklenen kısıtlamalar dahil olmak üzere çözücüyü hemen yeniden çalıştırabiliriz. PicoSAT bize yeni bir model sunuyor ve çözüm geçerli olana kadar yukarıdaki adımları tekrarlamaya devam ediyoruz.

Bu oldukça etkilidir; saniyenin küçük bir bölümünde 15 × 15 ve 20 × 20 örnekleri çözer.

( Bir süre önce artan bir SAT çözücüsünde bağlı bölgeleri etkileşimli olarak sınırlama fikrini önerdiği için Lopsy'ye teşekkürler .)

Puzzle-nurikabe.com'dan bazı büyük test vakaları

15 × 15 sabit bulmacadan oluşan rastgele bir sayfa ( 5057541 , 5122197 , 5383030 , 6275294 , 6646970 , 6944232 ):

15,15 1,5,1 3,9,1 5,4,2 1,6,2 2,11,2 2,2,3 3,9,3 2,4,4 1,10,4 5,12,4 3,1,5 1,3,5 3,8,5 1,13,5 5,5,6 1,12,6 1,2,8 2,9,8 1,1,9 2,6,9 6,11,9 3,13,9 5,2,10 2,4,10 4,10,10 1,5,11 2,12,11 2,3,12 2,8,12 5,10,12 1,5,13 1,9,13 1,6,14 1,8,14
15,15 4,2,0 2,5,0 1,3,1 2,14,2 1,3,3 2,11,3 1,13,3 1,5,4 11,7,4 1,9,4 1,4,5 1,8,5 2,10,5 12,14,5 3,5,6 1,4,7 2,10,7 3,9,8 4,0,9 1,4,9 1,6,9 3,10,9 1,5,10 1,7,10 8,9,10 1,1,11 10,3,11 2,11,11 6,0,12 1,11,13 2,9,14 1,12,14
15,15 2,2,0 8,10,0 2,3,1 2,14,2 2,3,3 3,5,3 3,9,3 2,11,3 5,13,3 6,0,4 3,7,4 3,3,5 2,11,5 2,6,6 1,8,6 1,4,7 2,10,7 1,6,8 2,8,8 5,3,9 2,11,9 2,7,10 7,14,10 2,1,11 4,3,11 2,5,11 1,9,11 2,11,11 2,0,12 4,6,13 1,11,13 3,4,14 1,12,14
15,15 2,0,0 2,4,0 3,6,1 2,10,1 1,13,1 2,5,2 2,12,2 3,0,3 2,2,3 4,7,3 2,9,3 1,14,3 1,4,4 1,8,4 2,12,5 4,2,6 3,4,6 1,14,6 7,7,7 1,10,8 2,12,8 3,2,9 2,14,9 2,0,10 2,6,10 1,10,10 2,5,11 4,7,11 2,12,11 1,14,11 3,2,12 3,9,12 1,1,13 2,4,13 3,8,13 2,10,14 5,14,14
15,15 1,3,0 1,14,0 3,7,1 3,10,1 2,13,1 3,1,2 4,5,2 2,12,3 3,3,4 1,8,4 1,1,5 3,5,5 1,9,5 5,13,5 3,3,6 1,8,6 2,2,7 2,12,7 1,6,8 1,8,8 2,11,8 2,1,9 4,5,9 2,9,9 2,13,9 2,6,10 4,11,10 1,2,11 3,9,12 2,13,12 3,1,13 2,4,13 3,7,13 1,0,14
15,15 2,8,0 2,4,1 2,7,1 1,10,1 6,4,3 1,1,4 12,5,4 3,11,4 5,13,4 3,10,5 3,0,6 1,6,6 2,8,6 4,13,7 2,3,8 1,6,8 3,8,8 2,14,8 2,4,9 5,1,10 4,3,10 1,9,10 6,13,10 3,8,11 1,10,11 3,4,13 2,7,13 3,10,13 1,6,14 1,14,14

20 × 20 normal yapbozdan oluşan rastgele bir sayfa ( 536628 , 3757659 ):

20,20 1,0,0 3,2,0 2,6,0 1,13,0 3,9,1 3,15,1 2,7,2 3,13,2 3,0,3 2,3,3 3,18,3 3,5,4 2,9,4 2,11,4 2,16,4 1,0,5 2,7,5 1,10,5 1,19,5 3,2,6 1,11,6 2,17,6 2,0,7 3,4,7 5,6,7 2,9,7 4,13,7 3,15,7 1,3,8 1,10,8 1,14,9 2,18,9 3,1,10 2,4,10 1,8,10 1,10,10 3,12,10 3,16,10 1,9,11 1,17,11 2,19,11 2,0,12 2,2,12 1,4,12 4,6,12 2,13,12 2,15,12 1,14,13 2,17,13 1,3,14 2,5,14 4,7,14 2,15,14 3,0,15 1,2,15 2,13,15 3,18,15 3,7,16 7,10,16 1,17,16 2,0,17 2,3,17 2,5,17 3,11,17 3,15,17 1,0,19 1,2,19 1,4,19 2,6,19 5,8,19 1,11,19 1,13,19 3,15,19 2,18,19
20,20 1,0,0 1,4,0 5,8,0 1,17,0 1,19,0 2,17,2 3,6,3 2,10,3 2,12,3 4,14,3 6,0,4 3,4,4 4,7,4 1,11,4 1,18,4 1,6,5 3,12,5 4,15,5 4,4,6 2,16,6 2,19,6 6,0,7 3,10,7 2,12,8 2,17,8 3,3,9 2,5,9 4,8,9 2,10,9 3,0,10 1,2,10 5,14,10 2,16,10 2,19,10 7,7,11 3,12,12 2,17,12 2,2,13 4,4,13 3,6,13 4,14,13 3,0,14 1,3,14 1,5,14 3,16,14 1,2,15 1,9,15 2,11,15 5,13,15 3,19,15 1,4,16 3,6,16 1,3,17 1,12,17 1,14,17 1,16,17 6,0,19 2,2,19 3,5,19 2,7,19 5,9,19 1,11,19 2,13,19 1,15,19 4,17,19

3

GLPK , (rakip olmayan) 2197 bayt

Bu rakip olmayan bir giriş, çünkü

  • Giriş veri formatını takip etmiyorum (GLPK yalnızca dosyalardan giriş verilerini okuyabileceğinden) ve
  • GLPK, RIO'da mevcut değil gibi görünüyor.

Hala ungolfed ama yine de işlevsel bir sürümü kaydedeceğim. Geri bildirime bağlı olarak, kısaltmaya + ilgi varsa bir açıklama eklemeye çalışabilirim. Şimdiye kadar, kısıtlama adları yerinde dokümanlar olarak işlev görmektedir.

Ana fikir, ipucu konumunda önceden belirlenmiş bir kaynağı olan korunmuş bir akış değişkeni ekleyerek "bitişik adalar" kısıtlamasını kodlamaktır. Karar değişkeni is_islanddaha sonra yerleştirilebilir evyelerin rolünü oynar. Bu akışın toplam toplamını en aza indirerek, adalar optimumda bağlı kalmaya zorlanır. Diğer kısıtlamalar, doğrudan çeşitli kuralları uygular. Beni hala şaşırtan şey island_fields_have_at_least_one_neighbor.

Bununla birlikte, bu formülasyonun performansı harika değildir. Tüm karmaşıklığı büyük miktarda kısıtlamayla doğrudan yiyerek, çözücü 15 x 15 örneği için 15 saniyeye yakın bir zaman alır.

Kod (hala çözülmemiş)

# SETS
param M > 0, integer; # length
param N > 0, integer; # width
param P > 0, integer; # no. of islands

set X := 0..N-1;  # set of x coords
set Y := 0..M-1;  # set of y coords
set Z := 0..P-1;  # set of islands

set V := X cross Y;
set E within V cross V := setof{
  (sx, sy) in V, (tx, ty) in V :

  ((abs(sx - tx) = 1) and (sy = ty)) or 
  ((sx = tx) and (abs(sy - ty) = 1))
} 
  (sx, sy, tx, ty);


# PARAMETERS
param islands{x in X, y in Y, z in Z}, integer, default 0;
param island_area{z in Z} := sum{x in X, y in Y} islands[x, y, z];

# VARIABLES
var is_river{x in X, y in Y}, binary;
var is_island{x in X, y in Y, z in Z}, binary;
var flow{(sx, sy, tx, ty) in E, z in Z} >= 0;

# OBJECTIVE
minimize obj: sum{(sx, sy, tx, ty) in E, z in Z} flow[sx, sy, tx, ty, z];

# CONSTRAINTS
s.t. islands_are_connected{(x, y) in V, z in Z}:

    islands[x, y, z] 
  - is_island[x, y, z]
  + sum{(sx, sy, tx, ty) in E: x = tx and y = ty} flow[sx, sy, x, y, z]
  - sum{(sx, sy, tx, ty) in E: x = sx and y = sy} flow[x, y, tx, ty, z]
  = 0;


s.t. island_contains_hint_location{(x, y) in V, z in Z}:

    is_island[x, y, z] >= if islands[x, y, z] > 0 then 1 else 0;


s.t. each_square_is_river_or_island{(x, y) in V}:

    is_river[x, y] + sum{z in Z} is_island[x, y, z] = 1;


s.t. islands_match_hint_area{z in Z}:

    sum{(x, y) in V} is_island[x, y, z] = island_area[z];


s.t. river_has_no_lakes{(x,y) in V: x > 0 and y > 0}:

  3 >= is_river[x, y] + is_river[x - 1, y - 1]
     + is_river[x - 1, y] + is_river[x, y - 1];


s.t. river_squares_have_at_least_one_neighbor{(x, y) in V}:

    sum{(sx, sy, tx, ty) in E: x = tx and y = ty} is_river[sx, sy] 
 >= is_river[x, y];


s.t. island_fields_have_at_least_one_neighbor{(x, y) in V, z in Z: island_area[z] > 1}:

    sum{(sx, sy, tx, ty) in E: x = tx and y = ty} is_island[sx, sy, z]
 >= is_island[x, y, z];


s.t. islands_are_separated_by_water{(x, y) in V, z in Z}:

    sum{(sx, sy, tx, ty) in E, oz in Z: x = sx and y = sy and z != oz} is_island[tx, ty, oz]
 <= 4 * P * (1 - is_island[x, y, z]);

solve;

for{y in M-1..0 by -1}
{
    for {x in X} 
    {
        printf "%s", if is_river[x, y] = 1 then "." else "#";
    }
    printf "\n";
}

Sorun verileri

5 x 5

data;
param M := 5;
param N := 5;
param P := 5;
param islands :=
# x,y,z,area
  0,1,0,3
  4,1,1,1
  0,4,2,2
  2,4,3,2
  4,4,4,2;
end;

7 x 7

data;
param M := 7;
param N := 7;
param P := 8;
param islands :=
# x,y,z,area
  0,0,0,2 
  3,1,1,2 
  6,1,2,2 
  4,3,3,2 
  2,4,4,2 
  0,6,5,8 
  2,6,6,1 
  4,6,7,3;
end;

15 x 15

data;
param M := 15;
param N := 15;
param P := 34;
param islands :=
# x,y,   z,area
5,  1,   0, 1
9,  1,   1, 3
4,  2,   2, 5
6,  2,   3, 1
11, 2,   4, 2
2,  3,   5, 2
9,  3,   6, 3
4,  4,   7, 2
10, 4,   8, 1
12, 4,   9, 5
1,  5,  10, 3
3,  5,  11, 1
8,  5,  12, 3
13, 5,  13, 1
5,  6,  14, 5
12, 6,  15, 1
2,  8,  16, 1
9,  8,  17, 2
1,  9,  18, 1
6,  9,  19, 2
11, 9,  20, 6
13, 9,  21, 3
2,  10, 22, 5
4,  10, 23, 2
10, 10, 24, 4
5,  11, 25, 1
12, 11, 26, 2
3,  12, 27, 2
8,  12, 28, 2
10, 12, 29, 5
5,  13, 30, 1
9,  13, 31, 1
6,  14, 32, 1
8,  14  33, 1;
end;

kullanım

Yüklediniz glpsol, tek bir dosya olarak modelleyin (örn. river.mod), Ayrı dosyalara veri girin (örn. 7x7.mod). Sonra:

glpsol -m river.mod -d 7x7.mod

Bu artı sabır, çözümü belirtilen çıktı biçiminde ("bazı" tanı çıktılarıyla birlikte) yazdırır.


2
Bu cevabın, diğer insanların işe yarayıp yaramadığını doğrulaması mümkün olduğu için yarışan olarak düşünülmesi gerektiğini düşünüyorum. ES formatındaki farklılıklar, makul IO formatının kabul edilmesi gerektiği varsayımıyla ele alınmalıdır.
fəˈnɛtɪk

2
@ fəˈnɛtɪk Kabul etti. Özellikle TIO'da çalıştırılabilecek bir cevap gerektiren ngn'ın ödülü için uygun değildi, ancak bu sorunun kendisinin bir zorunluluğu değil.
Anders Kaseorg

Golf oynamaya başlamadığım göz önüne alındığında, henüz rekabet etmediğini düşünmeyeceğim. Gereksiz tüm kısıtlamaları budadığımdan emin olduktan sonra, tüm bildirimleri bir kerelik harcayacağım.
ojdo

3

Python 3 , 1295 bayt

Bu sadece bir python çözümüdür. Hiçbir kitaplık kullanmaz ve kartı standart girdi ile yükler. Daha fazla açıklama gelecek. Bu kadar büyük bir golf için ilk denemem. Altta yorumlanmış ve hiç golf edilmeyen koda bir bağlantı vardır.

L,S,O,R,F=len,set,None,range,frozenset
U,N,J,D,I=S.update,F.union,F.isdisjoint,F.difference,F.intersection
def r(n,a,c):
 U(c,P)
 if L(I(N(Q[n],C[n]),a))<2:return 1
 w=D(P,N(a,[n]));e=S();u=S([next(iter(w))])
 while u:n=I(Q[u.pop()],w);U(u,D(n,e));U(e,n)
 return L(e)==L(w)
def T(a,o,i,c,k):
 s,p,m=a
 for _ in o:
  t=s,p,N(m,[_]);e=D(o,[_])
  if t[2] in c:o=e;continue
  c.add(t[2]);n=D(Q[_],m);U(k,n)
  if not J(i,n)or not r(_,N(m,i),k):o=e
  elif s==L(t[2]):yield t
  else:yield from T(t,N(e,n),i,c,k)
s,*p=input().split()
X,Y=eval(s)
A=[]
l=1,-1,0,0
P=F((x,y)for y in R(Y)for x in R(X))
exec("Q%sl,l[::-1]%s;C%s(1,1,-1,-1),l[:2]*2%s"%(('={(x,y):F((x+i,y+j)for i,j in zip(',')if X>x+i>-1<y+j<Y)for x,y in P}')*2))
for a in p:a,x,y=eval(a);k=x,y;A+=[(a,k,F([k]))]
A.sort(reverse=1)
k=F(a[1]for a in A)
p=[O]*L([a for a in A if a[0]!=1])
g,h=p[:],p[:]
i=0
while 1:
 if g[i]is O:h[i]=S();f=O;g[i]=T(A[i],Q[A[i][1]],D(N(k,*p[:i]),[A[i][1]]),S(),h[i])
 try:p[i]=g[i].send(f)[2]
 except:
  f=I(N(k,*p[:i]),h[i]);g[i]=p[i]=O;i-=1
  while J(p[i],f):g[i]=p[i]=O;i-=1
 else:
  i+=1
  if i==L(p):
   z=N(k,*p)
   if not any(J(z,F(zip([x,x+1]*2,[y,y,y+1,y+1])))for x in R(X-1)for y in R(Y-1)):break
   for c in h:U(c,z)
b=[X*['.']for i in R(Y)]
for x,y in z:b[y][x]='#'
for l in b[::-1]:print(''.join(l))

Çevrimiçi deneyin!

Bak un-golfed kodu .

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.