Java ( daha az grotesk: 8415 5291 3301)
Tamam. Temel olarak, hiç kimsenin bir çözüm yollamadığı için utanıyorum. Bu yüzden birkaç gün önce bu sorunu çözmeye çalıştım, b / c harika. . GitHub ile ilerlememi izlemek için bu linki takip edin.
Düzenle
Yeni çözücü sürümü, MT0 tarafından tanımlandığı şekilde düzeltilmiş döngü kontrolcüsü ile çok daha "golf oyunu". Ayrıca, VM için ne kadar bellek kullanılabilir olduğunu değiştirerek ayarlanabilen hızlı ileri sarma rotalarını da destekler. En son BÜYÜK düzenleme: birkaç küçük indeks hatası ve erken optimizasyonlar olduğumu fark ettim, bu da oldukça fazla sayıda kazanımın dikkate alınmamasıyla sonuçlandı. Demek dikkatlice düzeltildi. Yeni sürüm hem daha küçük hem de daha küçük. Referans rotamız java -Xmx2GB ZombieHordeMin
için püf noktası oldukça iyi yapıyor (uyarılmalıdır, biraz zaman alacaktır).
Serin factoid
Büyüleyici bir bükülmede, 24 uzunluğundaki MANY çözümleri var ve çözücüm, MT0'lardan farklı bir tane buluyor, ancak prensip olarak aynı , diğer bağlantı noktalarını ziyaret ederek başlaması dışında 1
. Büyüleyici! Tamamen insan sezgisine karşı, ama tamamen geçerli.
Çözümün Önemli Noktaları
İşte benim. (Kısmen) golf oynamak, b / c üstel, neredeyse kaba kuvvetli bir çözücü. Bir IDDFS (yinelemeli derinlik derinliği ilk arama) algoritması kullanıyorum, bu yüzden atlamayan harika bir genel çözücü, bu yüzden OP'nin sorusunun her iki bölümünü de çözüyor :
- Kazanan bir rota bulunursa (sonsuz zombiler), 'x' çıktısı alın.
- Tüm yollar ölümle bitiyorsa (sonlu zombiler), öldürülen en fazla sayıda zombi ortaya çıkar.
Yeterince güç, hafıza ve zaman verin, sadece yavaş ölüm haritalarını bile yapacak. Bu çözücüyü geliştirmek için biraz daha zaman harcadım ve daha fazlası yapılabilirken, şimdi biraz daha iyi. Ayrıca MT0'ın en iyi sonsuz-zombiler çözümü konusundaki tavsiyelerini birleştirdim ve önceki sürümün bulmasını engelleyen kazancımdan birkaç erken optimizasyon aldım ve şimdi tarif edilen MT0 ile benzer bir çözüm buldum.
Birkaç diğer önemli özellik:
- Belirtildiği gibi, mümkün olan en kısa kazanma rotasını bulmak için bir IDDFS kullanır.
- Özünde bir DFS olduğu için, her rotanın kahramanımızın ölümüyle sona erip bitmediğini ve öldürülen çoğu zombide "en iyi" rotayı takip edip etmediğini de keşfedecektir. Bir kahraman öl!
Golf amaçlı, Removed izlemesini daha ilginç kılmak için algoritmayı geliştirdim . Ungolded versiyonunu görmek için github linklerinden birini takip edin.
Ayrıca, bir takım yorumlar da var, bu yüzden yaklaşımımla ilgili kendi çözüm kurgunuz için yeniden uygulamaktan çekinmeyin ya da nasıl yapılması gerektiğini gösterin!
- Hafızaya uyumlu rota hızlı ileri sarma
- Kullanılabilir sistem hafızasına kadar, ölümle sonuçlanmayan "bitiş yollarını" izleyecektir.
- Süslü bir rota sıkıştırma ve dekompresyon rutini kullanarak, daha önce ziyaret edilen tüm rotaların yeniden keşfedilmesini önlemek için önceki bir IDDFS yinelemesinden elde edilen ilerleme geri yüklenir.
- Kasıtlı bir yan bonus olarak, çıkmaz bir rota ayrıcısı olarak davranır. Çıkmaz yollar saklanmaz ve gelecekteki IDDFS derinliklerinde bir daha asla ziyaret edilmeyecektir.
Çözücünün tarihi
- Birkaç adım ileriye dönük bir algoritma denedim ve çok basit senaryolar için çalışırlarsa, sonuçta düz düşerler.
- Sonra iki adım ileriye dönük bir algoritma denedim, ki bu tatmin edici değildi.
- Daha sonra, bu yaklaşımın DFS'ye indirgenebilir olduğunu anladığımda n adımlı bir bakış açısı oluşturmaya başladım, ancak DFS çok daha ... daha zarif.
- DFS'yi oluştururken, IDDFS'nin (a) en iyi HERO (ölüm) yolunu veya (b) ilk kazanan çevrimi bulmasını sağlayacağı aklıma geldi.
- Kazanma döngüsü denetleyicisi oluşturmanın kolay olduğu, ancak başarılı bir denetleyiciye ulaşmadan önce birkaç çok yanlış yinelemeden geçmek zorunda kaldım.
- Algoritmamın kör etmesine neden olan üç erken erken optimizasyon çizgisini kaldırmak için MT0'ın kazandığı yolda etkili oldu.
- IDDFS çağrıları arasında gereksiz yere yeniden çalışmayı önlemek için verdiğiniz tüm belleği kullanacak ve ayrıca çıkmaz rotaları bellek sınırlarına kadar kaldıracak bir adaptif rota önbellekleme algoritması eklendi.
(Golf) kodu
Kodda (ungolfed sürümünü buradan veya buradan alın ):
import java.util.*;public class ZombieHordeMin{int a=100,b,m,n,i,j,z,y,D=0,R,Z,N;int p[][][];Scanner in;Runtime rt;int[][]r;int pp;int dd;int[][]bdr;int ww;int[][]bwr;int[][]faf;int ff;boolean ffOn;public static void main(String[]a){(new ZombieHordeMin()).pR();}ZombieHordeMin(){in=new Scanner(System.in);rt=Runtime.getRuntime();m=in.nextInt();N=in.nextInt();p=new int[m+1][m+1][N+1];int[]o=new int[m+1];for(b=0;b<N;b++){i=in.nextInt();j=in.nextInt();z=in.nextInt();o[i]++;o[j]++;D=(o[i]>D?o[i]:D);p[i][j][++p[i][j][0]]=z;if(i!=j)p[j][i][++p[j][i][0]]=z;D=(o[j]>D?o[j]:D);}m++;}void pR(){r=new int[5000][m+3];r[0][0]=a;Arrays.fill(r[0],1,m,1);r[0][m]=1;r[0][m+1]=0;r[0][m+2]=0;ww=-1;pp=dd=0;pR(5000);}void pR(int aMD){faf=new int[D][];ff=0;ffOn=true;for(int mD=1;mD<=aMD;mD++){System.out.printf("Checking len %d\n",mD);int k=ffR(0,mD);if(ww>-1){System.out.printf("%d x\n",ww+1);for(int win=0;win<=ww;win++)System.out.printf(" %d:%d,%d-%d",win,bwr[win][0],bwr[win][1],bwr[win][2]);System.out.println();break;}if(k>0){System.out.printf("dead max %d kills, %d steps\n",pp,dd+1);for(int die=0;die<=dd;die++)System.out.printf(" %d:%d,%d-%d",die,bdr[die][0],bdr[die][1],bdr[die][2]);System.out.println();break;}}}int ffR(int dP,int mD){if(ff==0)return pR(dP,mD);int kk=0;int fm=ff;if(ffOn&&D*fm>rt.maxMemory()/(faf[0][0]*8+12))ffOn=false;int[][]fmv=faf;if(ffOn){faf=new int[D*fm][];ff=0;}for(int df=0;df<fm;df++){dS(fmv[df]);kk+=pR(fmv[df][0],mD);}fmv=null;rt.gc();return kk==fm?1:0;}int pR(int dP,int mD){if(dP==mD)return 0;int rT=0;int dC=0;int src=r[dP][m];int sa=r[dP][0];for(int dt=1;dt<m;dt++){for(int rut=1;rut<=p[src][dt][0];rut++){rT++;r[dP+1][0]=sa-p[src][dt][rut]+r[dP][dt];for(int cp=1;cp<m;cp++)r[dP+1][cp]=(dt==cp?1:r[dP][cp]+1);r[dP+1][m]=dt;r[dP+1][m+1]=rut;r[dP+1][m+2]=r[dP][m+2]+p[src][dt][rut];if(sa-p[src][dt][rut]<1){dC++;if(pp<r[dP][m+2]+sa){pp=r[dP][m+2]+sa;dd=dP+1;bdr=new int[dP+2][3];for(int cp=0;cp<=dP+1;cp++){bdr[cp][0]=r[cp][m];bdr[cp][1]=r[cp][m+1];bdr[cp][2]=r[cp][0];}}}else{for(int chk=0;chk<=dP;chk++){if(r[chk][m]==dt){int fR=chk+1;for(int cM=0;cM<m+3;cM++)r[dP+2][cM]=r[dP+1][cM];for(;fR<=dP+1;fR++){r[dP+2][0]=r[dP+2][0]-p[r[dP+2][m]][r[fR][m]][r[fR][m+1]]+r[dP+2][r[fR][m]];for(int cp=1;cp<m;cp++)r[dP+2][cp]=(r[fR][m]==cp?1:r[dP+2][cp]+1);r[dP+2][m+2]=r[dP+2][m+2]+p[r[dP+2][m]][r[fR][m]][r[fR][m+1]];r[dP+2][m]=r[fR][m];r[dP+2][m+1]=r[fR][m+1];}if(fR==dP+2&&r[dP+2][0]>=r[dP+1][0]){ww=dP+1;bwr=new int[dP+2][3];for(int cp=0;cp<dP+2;cp++){bwr[cp][0]=r[cp][m];bwr[cp][1]=r[cp][m+1];bwr[cp][2]=r[cp][0];}return 0;}}}dC+=pR(dP+1,mD);if(ww>-1)return 0;}for(int cp=0;cp<m+3;cp++)r[dP+1][cp]=0;}}if(rT==dC)return 1;else{if(ffOn&&dP==mD-1)faf[ff++]=cP(dP);return 0;}}int[]cP(int dP){int[]cmp=new int[dP*2+3];cmp[0]=dP;cmp[dP*2+1]=r[dP][0];cmp[dP*2+2]=r[dP][m+2];for(int zip=1;zip<=dP;zip++){cmp[zip]=r[zip][m];cmp[dP+zip]=r[zip][m+1];}return cmp;}void dS(int[]cmp){int[]lv=new int[m];int dP=cmp[0];r[dP][0]=cmp[dP*2+1];r[dP][m+2]=cmp[dP*2+2];r[0][0]=100;r[0][m]=1;for(int dp=1;dp<=dP;dp++){r[dp][m]=cmp[dp];r[dp][m+1]=cmp[dP+dp];r[dp-1][cmp[dp]]=dp-lv[cmp[dp]];r[dp][m+2]=r[dp-1][m+2]+p[r[dp-1][m]][cmp[dp]][cmp[dP+dp]];r[dp][0]=r[dp-1][0]+r[dp-1][cmp[dp]]-p[r[dp-1][m]][cmp[dp]][cmp[dP+dp]];lv[cmp[dp]]=dp;}for(int am=1;am<m;am++)r[dP][am]=(am==cmp[dP]?1:dP-lv[am]+1);}}
Yaptığım değişiklikleri izlemek için, burada github'dan kodu alın . İşte kullandığım diğer haritalar.
Çıktı örneği
Referans çözümü için örnek çıktı:
$ java -d64 -Xmx3G ZombieHordeMin > reference_route_corrected_min.out
5 6 1 2 4 2 3 4 3 1 4 2 4 10 2 5 10 1 1 50
Checking len 1
Checking len 2
Checking len 3
Checking len 4
Checking len 5
Checking len 6
Checking len 7
Checking len 8
Checking len 9
Checking len 10
Checking len 11
Checking len 12
Checking len 13
Checking len 14
Checking len 15
Checking len 16
Checking len 17
Checking len 18
Checking len 19
Checking len 20
Checking len 21
Checking len 22
Checking len 23
Checking len 24
25 x
0:1,0-100 1:3,1-97 2:1,1-95 3:2,1-94 4:5,1-88 5:2,1-80 6:4,1-76 7:2,1-68 8:1,1-70 9:2,1-68 10:1,1-66 11:2,1-64 12:1,1-62 13:2,1-60 14:1,1-58 15:2,1-56 16:1,1-54 17:2,1-52 18:1,1-50 19:2,1-48 20:1,1-46 21:2,1-44 22:1,1-42 23:2,1-40 24:1,1-38
Bu şekilde rota çıkışını okuyun step
:: source
, route-to-get-here
- ammo
. Yani yukarıdaki çözümde şöyle okursunuz:
- Adımda
0
, 1
cephane ile karakolda 100
.
- Adımda
1
, cephane 1
bitene kadar karakol bulmak için rotayı kullanın3
97
- Adımda
2
, cephane 1
bitene kadar karakol bulmak için rotayı kullanın1
95
- ...
Kapanış notları
Bu yüzden umarım çözümümü yenmeyi zorlaştırdım, ancak LÜTFEN LÜTFEN! Bana karşı kullanın, bazı paralel işlemlere, daha iyi grafik teorisine vb. Ekleyin. Bu yaklaşımı geliştirebileceğimi düşündüğüm birkaç şey :
- algoritma ilerledikçe agresif bir şekilde "azaltma" döngülerine gerek duymadan geriye çekilmeyi keser.
- Bir örnek: Örnek problemde, 1-2-3 döngülerine ve diğer permütasyonları "bir adım" olarak düşünün, böylece daha hızlı bir şekilde döngü sonlandırmak için yolumuzu yapabiliriz.
- Örneğin, 1. düğümdeyseniz, (a) 2'ye, (b) 1'e, (c) 1-2-3'ten bir adım olarak geçebilirsiniz. Bu, bir çözücünün derinliği genişliğe katlamasına izin vererek, belirli bir derinlikte rota sayısını artırarak uzun döngüler için çözüme gitme süresini büyük ölçüde hızlandırır.
cull ölü yollar. Mevcut çözümüm, belirli bir yolun sonlandırıldığını ve her seferinde yeniden keşfetmesi gerektiğini "hatırlamıyor". En erken anı ölümün kesin olduğu ve asla ilerlemeyeceği bir rotada takip etmek daha iyi olacaktır. bunu yaptı...
- Dikkatli olursanız, ölü yol boşluğu alt yol boşluğu olarak uygulayabilirsiniz. Örneğin, 1-2-3-4 her zaman ölümle sonuçlanırsa ve çözücü 1-3-1-2-3-4 güzergahını test etmek üzereyse, sona ermesini garanti ettiği için o yolu düşürmeyi derhal durdurmalıdır. hayal kırıklığı içinde. Dikkatli bir matematikle öldürme sayısını hesaplamak yine de mümkün olacaktı.
Belleği zamana saran ya da takip eden çıkmaz rotaların saldırgan bir şekilde kaçınmasına izin veren başka herhangi bir çözüm. Bunu da yaptım!
1
0 mühimmat ile başlamak dışında mı? Grafik tek yönlü mü?