Bu soruna yaklaşmanın birçok yolu vardır. Verinin raster formatı, raster tabanlı bir yaklaşım önerir; Bu yaklaşımları gözden geçirirken, problemin bir ikili tamsayılı lineer program olarak formülasyonu umut verici görünmektedir, çünkü birçok CBS alan seçim analizinin ruhundadır ve bunlara kolayca adapte edilebilir.
Bu formülasyonda, "fayans" olarak adlandıracağım dolum poligonunun (lar) mümkün olan tüm pozisyonlarını ve yönlerini sıralıyoruz. Her karo ile ilişkili "iyiliğinin" bir ölçüsüdür. Amaç, toplam iyiliği mümkün olduğu kadar büyük olan üst üste binmeyen karolardan oluşan bir koleksiyon bulmaktır. Burada, her döşemenin iyiliğini kapsadığı alan olarak alabiliriz. (Daha fazla veri bakımından zengin ve sofistike karar ortamlarında, iyiliği, her bir döşemenin içerdiği hücrelerin özelliklerinin, belki de görünürlükle ilgili özelliklerin, diğer şeylerin yakınlığına vb. Bağlı olarak hesaplıyor olabiliriz.)
Bu problem üzerindeki kısıtlamalar basitçe, bir çözelti içindeki hiçbir iki döşemenin üst üste gelemeyeceğidir.
Bu, doldurulacak poligondaki hücrelerin sayılmasıyla ("bölge") 1, 2, ..., M , verimli bir şekilde hesaplanmaya elverişli bir şekilde biraz daha soyut olarak çerçevelenebilir . Herhangi bir kiremit yerleşimi, sıfırların ve diğerlerinin bir gösterge vektörüyle kodlanmış olabilir, bu da diğerlerinin kiremit ve sıfırlarla kaplı hücrelere karşılık gelmesine izin verir. Bu kodlamada, bir kiremit koleksiyonu hakkında gerekli tüm bilgiler gösterge vektörlerini toplayarak bulunabilir (her zamanki gibi bileşene göre bileşen): toplam, en az bir döşemenin bir hücreyi kapsadığı ve toplamın daha büyük olacağı yerlerde sıfırdan farklı olacaktır iki veya daha fazla fayans üst üste binen birden fazla yerde. (Toplam, örtüşme miktarını etkili bir şekilde sayar.)
Bir daha küçük soyutlama: Olası karo yerleşim kümesi kendisi sayılan demek olabilir 1, 2, ..., N . Herhangi bir kiremit yerleşimi kümesinin kendisinin seçimi, yerlilerin yerleştirilecek kiremitleri belirlediği bir gösterge vektörüne karşılık gelir.
İşte fikirleri düzeltmek için küçük bir örnek . Hesaplamaları yapmak için kullanılan Mathematica koduna eşlik eder , böylece programlama zorluğu (veya eksikliği) açıkça ortaya çıkar.
İlk olarak, döşenecek bir bölgeyi gösterelim:
region = {{0, 0, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};
Hücrelerini soldan sağa doğru numaralandırırsak, en baştan başlayarak, bölge için gösterge vektörünün 16 girişi vardır:
Flatten[region]
{0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
Aşağıdaki döşemeyi, tüm dönüşlerde 90 derecenin katları ile birlikte kullanalım:
tileSet = {{{1, 1}, {1, 0}}};
Rotasyon (ve yansımalar) oluşturmak için kod:
apply[s_List, alpha] := Reverse /@ s;
apply[s_List, beta] := Transpose[s];
apply[s_List, g_List] := Fold[apply, s, g];
group = FoldList[Append, {}, Riffle[ConstantArray[alpha, 4], beta]];
tiles = Union[Flatten[Outer[apply[#1, #2] &, tileSet, group, 1], 1]];
(Bu biraz opak hesaplama, bir döşemenin tüm olası dönüşlerini ve yansımalarını gösterdiğini ve sonra yinelenen sonuçları kaldırdığını gösteren /math//a/159159 adresindeki bir yanıtta açıklanmıştır .)
Döşemeyi burada gösterildiği gibi yerleştireceğimizi varsayalım:
Bu yerleşimde 3, 6 ve 7 numaralı hücreler kaplanmıştır. Bu gösterge vektörü tarafından belirlenir
{0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}
Bu döşemeyi bir sütunu sağa kaydırırsak, bu gösterge vektörü bunun yerine
{0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}
Fayansları her iki konuma aynı anda yerleştirmeye çalışmanın kombinasyonu , bu göstergelerin toplamı tarafından
{0, 0, 1, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0}
Yedinci pozisyondaki 2, bu örtüşmeyi bir hücrede gösterir (ikinci satır aşağı, soldan üçüncü sütun). Örtüşmek istemediğimiz için, herhangi bir geçerli çözümdeki vektörlerin toplamının 1'i geçmemesi gerekir.
Bu problem için fayanslar için 29 oryantasyon ve pozisyon kombinasyonunun mümkün olduğu ortaya çıktı. (Bu, ayrıntılı bir araştırmayı içeren basit bir kodlama biti ile bulundu.) Göstergelerini sütun vektörleri olarak çizerek 29 olasılığı da gösterebiliriz . (Satır yerine sütunları kullanmak gelenekseldir.) İşte, 16 satır (dikdörtgendeki her olası hücre için bir tane) ve 29 sütuna sahip olan sonuç dizisinin bir resmi:
makeAllTiles[tile_, {n_Integer, m_Integer}] :=
With[{ m0 = Length[tile], n0 = Length[First[tile]]},
Flatten[
Table[ArrayPad[tile, {{i, m - m0 - i}, {j, n - n0 - j}}], {i, 0, m - m0}, {j, 0, n - n0}], 1]];
allTiles = Flatten[ParallelMap[makeAllTiles[#, ImageDimensions[regionImage]] & , tiles], 1];
allTiles = Parallelize[
Select[allTiles, (regionVector . Flatten[#]) >= (Plus @@ (Flatten[#])) &]];
options = Transpose[Flatten /@ allTiles];
(Önceki iki gösterge vektörü soldaki ilk iki sütun olarak görünür.) Keskin gözlü okuyucu paralel işleme için çeşitli fırsatlar fark etmiş olabilir: bu hesaplamalar birkaç saniye sürebilir.
Yukarıdakilerin tümü, matris notasyonu kullanılarak kompakt bir şekilde yeniden düzenlenebilir:
F , M satırı ve N sütunu olan bir seçenek dizisidir .
X , N uzunluğundaki bir dizi döşeme yerleşiminin göstergesidir .
b , bir N- vektörüdür.
R , bölgenin göstergesidir; bir olduğunu M -vector.
Mümkün olan herhangi bir X çözeltisiyle ilişkilendirilen toplam "iyilik" , RFX'e eşittir , çünkü FX , X'in kapsadığı hücrelerin göstergesidir ve R'nin olduğu ürün bu değerleri toplar. ( Bölgedeki belirli alanları tercih etmek ya da önlemek için çözümler diliyorsak, R'yi ağırlıklandırabiliriz .) Bu maksimize edilecektir. Çünkü biz bunu ( RF ) olarak yazabiliriz . X , bir olan doğrusal fonksiyonu X : Bu önemli. (Aşağıdaki kodda, değişken RFc
içerir .)
Kısıtlamaları vardır o
X'in tüm unsurları negatif olmamalıdır;
X'in tüm elemanları 1'den küçük olmalıdır ( b'deki karşılık gelen giriş );
X'in tüm unsurları ayrılmaz olmalıdır.
Kısıtlayıcı (1) ve (2) bu yapmak doğrusal program üçüncü gereklilik, içine döner iken, tamsayı programı lineer.
Tam olarak bu şekilde ifade edilen tamsayılı doğrusal programları çözmek için birçok paket vardır . Onlar M ve N değerlerini onlarca, hatta yüzbinlerce üzerinde tutabiliyorlar. Bazı gerçek dünya uygulamaları için bu muhtemelen yeterince iyi.
İlk resmimiz olarak, önceki örnekte Mathematica 8'in LinearProgramming
komutunu kullanarak bir çözüm hesapladım . (Bu, doğrusal bir amaç işlevini en aza indirir . Amaç, işlev işlevini reddederek minimize etme kolayca maksimize olur.) 0.011 saniyede bir çözüm (karoların ve konumlarının listesi olarak) döndürür:
b = ConstantArray[-1, Length[options]];
c = -Flatten[region].options;
lu = ConstantArray[{0, 1}, Length[First[options]]];
x = LinearProgramming[c, -options, b, lu, Integers, Tolerance -> 0.05];
If[! ListQ[x] || Max[options.x] > 1, x = {}];
solution = allTiles[[Select[x Range[Length[x]], # > 0 &]]];
Gri hücreler hiç bölgede değil; beyaz hücreler bu çözeltiyle kaplanmadı.
Bu kadar iyi olan birçok başka tiltleri (el ile) çözebilirsiniz - ama daha iyisini bulamazsınız. Yani bu yaklaşımın potansiyel bir sınırlama var: size verir bir en iyi çözümü, birden fazla olduğunda bile. (Bazı geçici çözümler vardır: X'in sütunlarını yeniden sıralarsak, sorun değişmeden kalır, ancak yazılım sonuç olarak farklı bir çözüm seçer. Ancak, bu davranış tahmin edilemez.)
İkinci bir örnek olarak , daha gerçekçi olmak için, söz konusu bölgeyi düşünelim. Görüntüyü içe aktararak ve yeniden örnekleyerek, onu 69'a 81 ızgarayla temsil ettim:
Bölge, bu ızgaradan 2156 hücre içerir.
İşleri ilginç kılmak ve doğrusal programlama kurulumunun genelliğini göstermek için, bu bölgeyi olabildiğince iki çeşit dikdörtgenle kapatalım:
Biri 17'e 9 (153 hücre), diğeri 15'e 11 (165 hücre). İkincisi kullanmayı tercih edebiliriz, çünkü daha büyük, ancak birincisi daha ince ve daha dar yerlere sığabilir. Bakalım!
Program şimdi N = 5589 olası kiremit yerleşimini içeriyor . Bu oldukça büyük! 6.3 saniyelik bir hesaplamadan sonra, Mathematica bu on döşemeli çözümle geldi:
Bazı gevşeklikler nedeniyle ( .eg, sol alt karoyu sola doğru dört sütuna kaydırabiliriz), açıkça ondan biraz farklı olan başka çözümler de var.