Önce Genişlik Arama'da ziyaret edilen ülkeleri izleme


10

Bu yüzden bir Biding Blocks bulmacasında (sayı tipi) BFS uygulamaya çalışıyordum . Şimdi fark ettiğim en önemli şey, eğer bir 4*4tahtanız varsa , devletlerin sayısı kadar büyük olabilir, 16!bu yüzden tüm devletleri önceden numaralandıramam.

Öyleyse sorum şu ki, daha önce ziyaret edilen eyaletleri nasıl takip edebilirim? (Her sınıf örneği benzersiz bir tahta deseni içeren bir sınıf panosu kullanıyorum ve mevcut adımdan mümkün olan tüm adımları numaralandırarak oluşturulur).

Ben net arandı ve görünüşe göre sadece tamamlanmış önceki adıma geri gitmez AMA biz daha önce ziyaret edilmiş tüm adımları numaralandırırsanız yeniden çok ve daha sonra tekrar başka bir yolla önceki adıma geri dönebilirsiniz. Peki, tüm eyaletler önceden numaralandırılmadığında ziyaret edilen eyaletleri nasıl takip edebilirim? (halihazırda mevcut olan durumların mevcut adıma karşılaştırılması maliyetli olacaktır).


1
Yan Not: Bu soruyu göndermek için daha uygun bir Stack düşünemedim. Uygulama ayrıntılarının bu Yığın'da genellikle hoş karşılanmadığının farkındayım.
DuttaA

2
imo bu SE: AI için harika bir soru çünkü sadece uygulama değil, kavramın kendisi de. Bahsetmiyorum bile, soru birkaç saat içinde 4 yasal cevap aldı. (Arama başlığını düzenleme ve bir BFS etiketi oluşturma özgürlüğü aldı)
DukeZhou

Yanıtlar:


8

Daha setönce gördüğünüz durumları depolamak için (sözcüğün matematiksel anlamında, yani kopya içeremeyen bir koleksiyonda) kullanabilirsiniz. Bu konuda yapabileceğiniz işlemler şunlardır:

  • eleman ekleme
  • öğelerin zaten orada olup olmadığını test etmek

Hemen hemen her programlama dili, bu işlemlerin her ikisini de sabit olarak gerçekleştirebilen bir veri yapısı için zaten desteğe sahip olmalıdır (O(1)) zaman. Örneğin:

  • set Python'da
  • HashSet Java'da

İlk bakışta, gördüğünüz tüm durumları böyle bir sete eklemek, bellek açısından pahalı olacak gibi görünebilir, ancak sınırınız için zaten ihtiyacınız olan belleğe kıyasla çok kötü değil; dallanma faktörünüzb, sınırın büyüyecek b1 ziyaret ettiğiniz düğüm başına elemanlar (kaldır 1 sınırdan "ziyaret etmek" için düğüm ekleyin, b yeni halefler / çocuklar), ancak kümeniz yalnızca 1 ziyaret edilen düğüm başına fazladan düğüm.

Sözde kodda, wikipedia'daki sözde kodlaclosed_set tutarlı olmak için böyle bir küme (diyelim ki) Genişlik-İlk Arama'da aşağıdaki gibi kullanılabilir:

frontier = First-In-First-Out Queue
frontier.add(initial_state)

closed_set = set()

while frontier not empty:
    current = frontier.remove_next()

    if current == goal_state:
        return something

    for each child in current.generate_children()
        if child not in closed_set:    // This operation should be supported in O(1) time regardless of closed_set's current size
            frontier.add(child)

    closed_set.add(current)    // this should also run in O(1) time

(bu sözde kodun bazı varyasyonları da işe yarayabilir ve duruma bağlı olarak daha fazla veya daha az verimli olabilir; örneğin, closed_setzaten sınıra çocuk eklediğiniz tüm düğümleri içermek için de alabilir ve generate_children()çağrıdan tamamen kaçınabilirsiniz. currentzaten varsa closed_set.)


Yukarıda tarif ettiğim, bu sorunu ele almanın standart yolu olacaktır. Sezgisel olarak, farklı bir "çözümün" yeni bir halef devletleri listesinin sırasını, sınıra eklemeden önce her zaman rastgele hale getirmek olabileceğinden şüpheleniyorum. Bu şekilde, önceden sınıra önceden genişlettiğiniz durumları ara sıra ekleme sorununu ortadan kaldırmazsınız, ancak bunun sonsuz döngülere takılma riskini önemli ölçüde azaltması gerektiğini düşünüyorum.

Dikkatli olun : Bu çözümün, sonsuz döngülerden her zaman kaçındığını kanıtlayan herhangi bir resmi analiz bilmiyorum. Bunu kafamdan "çalıştırmaya" çalışırsam, sezgisel olarak, bir tür iş gerektirdiğinden şüphelenirim ve fazladan bellek gerektirmez. Şu anda düşünmediğim uç durumlar olabilir, bu yüzden de işe yaramayabilir, yukarıda açıklanan standart çözüm daha güvenli bir bahis olacaktır (daha fazla bellek pahasına).


1
Bunu yapabileceğim ama karşılaştırma süresi katlanarak artmaya başlayacak
DuttaA

3
@DuttaA Hiçbir karşılaştırma süresi katlanarak artmamalıdır. Bu kümeler, karma kümeler ya da seçtiğiniz dilde ne denirse verilsin, belirli bir durum içerip içermediklerini test edebilmelidir.S sürekli hesaplama karmaşıklığı ile O(1), zaten kaç öğe içerdiklerine bakılmaksızın . Onlar liste değil, zaten içerip içermediklerini test etmiyorlarSşu anda bulunan her elementle karşılaştırarak.
Dennis Soemers

1
Setin nasıl kullanılacağını açıklamak için bazı sözde kod ekledim, umarım bu bir şeyi netleştirebilir. Hiçbir zaman bütünün içinde dönmüyoruz closed_set, boyutu asla (asimptotik) hesaplama süremizi etkilememelidir.
Dennis Soemers

1
Aslında c ++ kullanarak yapıyordum
Hashing hakkında

3
@DuttaA C ++ ile muhtemelen bir std
Dennis Soemers

16

Dennis Soemers'in cevabı doğrudur: BFS Grafik Arama'da ziyaret edilen durumları takip etmek için bir HashSet veya benzer bir yapı kullanmalısınız.

Ancak, sorunuza tam olarak cevap vermiyor. Haklısın, en kötü durumda, BFS daha sonra 16 depolamanı gerektirecek! düğümleri. Setteki takma ve kontrol süreleri O (1) olsa da, yine de çok miktarda bellek gerekir.

Bunu düzeltmek için BFS kullanmayın . En basit problemler dışında herkes için zorlayıcıdır, çünkü en yakın hedef durumuna olan mesafelerde üstel olan hem zaman hem de bellek gerektirir .

Çok daha fazla bellek tasarruflu algoritma yinelemeli derinleşmedir . BFS'nin istenen tüm özelliklerine sahiptir, ancak yalnızca O (n) belleği kullanır; burada n, en yakın çözüme ulaşmak için hareket sayısıdır. Hala biraz zaman alabilir, ancak CPU ile ilgili sınırlardan çok önce bellek sınırlarına ulaşacaksınız.

Daha da iyisi, alana özgü bir sezgisel tarama geliştirin ve A * araması kullanın . Bu, yalnızca çok az sayıda düğümü incelemenizi ve aramanın doğrusal zamana çok daha yakın bir şeyde tamamlanmasını sağlar.


2
evet bu bulmacayı verimli bir şekilde çözmek isteyen insanlar için daha pratik bir cevaptır. Cevabım, BFS kullanmakta ısrar eden insanlar için (sadece eylemde görmek veya nasıl uygulanacağını veya herhangi bir nedenle öğrenmek istedikleri için). BFS'nin umarım depolaması gerekmeyeceğini unutmayın16!bu arada düğümler; bu sadece en kötü durum, o zamandan önce bir çözüm bulabilir.
Dennis Soemers

@DennisSoemers doğrudur ... Ayrıca haklısınız ... Sadece becerilerimi geliştirmeye çalışıyordum ... Daha sonra daha gelişmiş arama yöntemlerine
geçeceğim

BFS'nin kabul edilebilir yerel çözümleri iade edebileceği durumlar var mı? (81! * Tbd-değeri ve genişlik-öncesi gibi daha çok uğraşıyorum, tükenmeden kaçırması kolay olabilecek engelleme faktörleri olduğu için en uygun görünüyor. Şu anda gerçekten güçlü bir oyundan endişe etmiyoruz, öngörülemeyen bir oyun tahtası topolojisi dizisi üzerinden zayıf "genel performans.)
DukeZhou

2
@DukeZhou BFS genellikle sadece tam bir çözüm arandığında kullanılır. Erken durdurmak için, farklı kısmi çözümlerin göreceli kalitesini tahmin eden bir işleve ihtiyacınız vardır, ancak böyle bir işleve sahipseniz, bunun yerine muhtemelen A * kullanabilirsiniz!
John Doucette

"Oyunda hamle sayısı" demek yerine "hedefe ulaşmak için minimum hamle sayısını" öneriyorum. Oyundaki hamlelerin sayısını, sizi 16'dan birinden alan her hamle olarak düşünürdüm! yinelemeli derinleştirmenin kullandığından çok daha fazla bellek olan diğerlerine işaret eder.
NotThatGuy

7

Verilen cevaplar genellikle doğru olmakla birlikte , 15 bulmacasındaki bir BFS sadece oldukça mümkün değil, aynı zamanda 2005 yılında yapıldı! Yaklaşımı açıklayan makale burada bulunabilir:

http://www.aaai.org/Papers/AAAI/2005/AAAI05-219.pdf

Birkaç önemli nokta:

  • Bunu yapmak için harici bellek gerekiyordu - yani BFS, sabit sürücüyü RAM yerine depolama için kullandı.
  • Aslında sadece 15! / 2 devlet vardır, çünkü devlet alanı birbirine erişilemez iki bileşene sahiptir.
  • Bu durum sürgülü karo bulmacasında işe yarar çünkü devlet alanları seviyeden seviyeye çok yavaş büyür. Bu, herhangi bir seviye için gereken toplam belleğin durum alanının tam boyutundan çok daha küçük olduğu anlamına gelir. (Bu durum, durum alanının çok daha hızlı büyüdüğü Rubik Küpü gibi bir durum alanıyla tezat oluşturuyor.)
  • Kayan kiremit bulmacası yönlendirilmediğinden, yalnızca geçerli veya önceki katmandaki kopyalar için endişelenmeniz gerekir. Yönlendirilmiş bir alanda, aramanın herhangi bir önceki katmanında, işleri daha karmaşık hale getiren kopyalar oluşturabilirsiniz.
  • Korf'un orijinal çalışmasında (yukarıda bağlantılı) aramanın sonucunu gerçekten saklamadılar - arama sadece her seviyede kaç eyalet olduğunu hesapladı. İlk sonuçları kaydetmek istiyorsanız, WMBFS gibi bir şeye ihtiyacınız vardır ( http://www.cs.du.edu/~sturtevant/papers/bfs_min_write.pdf )
  • Durumlar diskte saklandığında, önceki katmanlardaki durumları karşılaştırmak için üç temel yaklaşım vardır.
    • Birincisi sıralama temelli. Ardıllardan iki dosyayı sıralarsanız, kopyaları bulmak için bunları doğrusal sırada tarayabilirsiniz.
    • İkincisi karma tabanlıdır. Ardılları dosyalarda gruplamak için bir karma işlevi kullanırsanız, kopyaları kontrol etmek için tam durum alanından daha küçük dosyaları yükleyebilirsiniz. (Burada iki karma işlev olduğunu unutmayın - biri dosyaya durum göndermek için diğeri bu dosyadaki durumları farklılaştırmak için.)
    • Üçüncüsü yapılandırılmış yinelenen algılamadır. Bu, karma tabanlı bir algılama şeklidir, ancak kopyaların hepsi oluşturulduktan sonra değil, oluşturulduklarında hemen kontrol edilebilecek şekilde yapılır.

Burada söylenecek çok şey var, ancak yukarıdaki kağıtlar çok daha fazla ayrıntı veriyor.


Bu harika bir cevap ... ama benim gibi noobs için değil :)) ... Ben bir programcının uzmanı değilim ..
DuttaA

Yönlendirilmemiş diğer katmanlardaki kopyalardan kaçınmanıza nasıl yardımcı olur? Şüphesiz, bir daire içinde 3 döşemeyi hareket ettirerek başka bir katmandaki düğüme geri dönebilirsiniz. Yönlendirilmiş bir şey varsa, kopyalardan kaçınmanıza yardımcı olur, çünkü daha kısıtlayıcıdır. Bağlantılı makale, yinelenen algılama hakkında konuşuyor, ancak yönlendirilmemiş veya yönlendirilmiş bir şeyden bahsetmiyor ve farklı düzeylerde yinelenmelerden kaçınmaktan bahsetmiyor gibi görünüyor (ancak bunu çok kısa bir taramamda kaçırmış olabilirim).
NotThatGuy

@NotThatGuy Yönlendirilmemiş bir grafikte ebeveyn ve çocuk, BFS'de bulundukları derinlikte en fazla 1 mesafe uzaktadır. Bunun nedeni, bir kez bulunduğunda yönlendirilmemiş kenarın diğerinin hemen sonra bulunacağını garanti etmesidir. Ancak, yönlendirilmiş bir grafikte, derinlik 10'daki bir durum, derinlik 2'deki çocukları üretebilir, çünkü derinlik 2'deki çocuğun diğer duruma geri dönmesi gerekmez (bu, derinlik 10 yerine derinliği 3 yapar) .
Nathan

@NotThatGuy Bir daire içinde 3 kutucuğu hareket ettirirseniz, bir döngü oluşturursunuz, ancak bir BFS bunu her iki yönde de eşzamanlı olarak keşfedecek, böylece sizi çok daha sığ derinliğe geri götürmeyecektir. Tam 3x2 sürgülü karo bu demoda gösterilmektedir ve nasıl olduklarını görmek için döngüleri takip edebilirsiniz: movingai.com/SAS/IDA
Nathan S.

1
harika özellikler. SE'ye hoş geldiniz: AI!
DukeZhou

3

İronik olarak cevap "istediğiniz sistemi kullanın." HashSet iyi bir fikirdir. Ancak, bellek kullanımı ile ilgili endişelerinizin asılsız olduğu ortaya çıkıyor. BFS bu tür problemlerde o kadar kötü ki, bu sorunu sizin için çözüyor.

BFS'nizin işlenmemiş bir durum yığını tutmanızı gerektirdiğini düşünün. Bulmacanın içinde ilerledikçe, uğraştığınız durumlar gittikçe daha farklı hale gelir, bu nedenle BFS'nizin her bir katının bakılacak durum sayısını kabaca 3 ile çarptığını görebilirsiniz.

Bu, BFS'nizin son katını işlerken, bellekte en az 16! / 3 durumunun olması gerektiği anlamına gelir. Önceden ziyaret ettiğiniz listenin belleğe sığmasını sağlamak için belleğe sığdırmanın yeterli olduğundan emin olmak için kullandığınız yaklaşım ne olursa olsun.

Diğerlerinin de belirttiği gibi, bu kullanılacak en iyi algoritma değildir. Soruna daha uygun bir algoritma kullanın.


2

15-bulmaca problemi 4x4 tahtada oynanır. Bunu kaynak kodunda uygulamak adım adım yapılır. İlk başta, oyun motorunun kendisi programlanmalıdır. Bu, oyunu bir insan operatör tarafından oynamaya izin verir. 15-bulmaca oyunu sadece bir serbest element vardır ve bu element üzerinde eylemler yürütülür. Oyun motoru dört olası komutu kabul eder: sol, sağ, yukarı ve aşağı. Diğer eylemlere izin verilmez ve oyunu sadece bu talimatlarla kontrol etmek mümkündür.

Oyunu oynamak için bir sonraki katman bir GUI'dir. Bu çok önemlidir, çünkü oyun motorunu test etmeyi ve oyunu elle çözmeye çalışmayı sağlar. Ayrıca, bir GUI önemlidir, çünkü potansiyel sezgiselliği bulmamız gerekir. Ve şimdi yapay zekanın kendisi hakkında konuşabiliriz. AI oyun motoruna komutlar göndermelidir (sol, sağ, yukarı ve aşağı). Bir çözücü için saf bir yaklaşım, kaba kuvvet arama algoritmasıdır, yani AI, hedef duruma ulaşılana kadar rastgele komutlar gönderir. Daha gelişmiş bir fikir, durum alanını azaltan bir çeşit örüntü veritabanı uygulamaktır. İlk genişlik araştırması doğrudan bir buluşsal yöntem değil, bir başlangıçtır. Olası hareketleri kronolojik olarak test etmek için bir grafik oluşturmak eşittir.

Mevcut durumların izlenmesi bir grafik ile yapılabilir. Her durum bir düğümdür, bir kimliği ve bir üst kimliği vardır. AI, grafikteki düğümleri ekleyebilir ve silebilir ve planlayıcı, hedefe giden bir yol bulmak için grafiği çözebilir. Programlama perspektifinden bakıldığında, 15 bulmacanın bir oyun motoru nesnedir ve birçok nesnenin listesi bir arraylisttir. Bir grafik sınıfında saklanırlar. Kaynak kodda bunu anlamak biraz zor, genellikle ilk deneme başarısız olur ve proje birçok hata üretir. Karmaşıklığı yönetmek için böyle bir proje genellikle akademik bir projede yapılır, yani, 100 sayfa ve daha fazla olabilecek bir makale yazmak için bir konudur.


1

Oyuna Yaklaşımlar

Kurulun sahip olduğu doğrudur. 16!olası durumlar. Grafik döngülerini içerebilen bir grafik ararken artıklık ve sonsuz döngüden kaçınmak için, bir karma kümesinin kullanılmasının öğrencilerin ilk yıl algoritma derslerinde öğrendikleri de doğrudur.

Ancak, eğer amaç bulmacayı en az bilgi işlem döngüsünde tamamlamaksa, bu önemsiz gerçekler uygun değildir. Genişlik ilk arama dikey hareket bulmacasını tamamlamak için pratik bir yol değildir. Bir genişlik ilk aramanın çok yüksek maliyeti, ancak hamle sayısının bir nedenle çok önemli olması durumunda gerekli olacaktır.

Alt-dizi İnişi

Eyaletleri temsil eden köşe noktalarının çoğu asla ziyaret edilmeyecektir ve ziyaret edilen her durumun iki ila dört giden kenarı olabilir. Her bloğun bir başlangıç ​​konumu ve bir son konumu vardır ve kart simetriktir. En büyük seçim özgürlüğü, açık alan dört orta konumdan biri olduğunda ortaya çıkar. En azı, açık alan dört köşe konumundan biri olduğundadır.

Makul bir eşitsizlik (hata) işlevi, tüm x eşitsizliklerinin toplamı artı tüm y eşitsizliklerinin toplamı ve açık alanın (orta, kenar) ortaya çıkması nedeniyle üç hareket özgürlüğü seviyesinden hangisinin var olduğunu sezgisel olarak temsil eden bir sayıdır. , köşe).

Bir dizi hamle gerektiren bir stratejiyi tamamlamaya doğru desteklemek için bloklar geçici olarak hedeflerinden uzaklaşabilse de, nadiren böyle bir stratejinin sekiz hareketi aştığı ve ortalama olarak son durumların karşılaştırılabileceği 5.184 permütasyon ürettiği bir durum vardır. yukarıdaki eşitsizlik işlevini kullanarak.

Blok 1 ile 15 arasındaki boş alan ve konumlar bir dizi nibble olarak kodlanırsa, algoritmayı hızlı hale getirmek için yalnızca toplama, çıkarma ve bit bilge işlemleri gerekir. Sekiz hamle kaba kuvvet stratejisini tekrarlamak, eşitsizlik sıfıra düşene kadar tekrarlanabilir.

özet

Bu algoritma döngü yapamaz, çünkü başlangıç ​​durumundan bağımsız olarak, zaten tamamlanmış olan bir başlangıç ​​durumu hariç, eşitsizliği azaltan sekiz hareketin en az biri vardır.

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.