Jawa ( kurang aneh: 8415 5291 3301)
Baik. Pada dasarnya, saya malu tidak ada yang mengajukan solusi. Jadi beberapa hari yang lalu saya mulai mencoba untuk menyelesaikan masalah ini, itu bagus. . Ikuti tautan itu untuk menyaksikan kemajuan saya di sana melalui GitHub.
Edit
Versi pemecah baru, lebih banyak "golf", dengan pemeriksa siklus yang diperbaiki sebagaimana diidentifikasi oleh MT0. Ini juga mendukung rute penerusan cepat, yang dapat disesuaikan dengan mengubah berapa banyak memori yang tersedia untuk VM. Sunting BIG terbaru : menyadari bahwa saya memiliki beberapa kesalahan indeks kecil dan optimasi prematur, yang mengakibatkan kegagalan untuk mempertimbangkan sejumlah besar jenis kemenangan. Jadi itu diperbaiki, hati-hati. Versi baru lebih kecil dan di bawah. Untuk rute referensi kami, java -Xmx2GB ZombieHordeMinlakukan triknya dengan cukup baik (diperingatkan, ini akan memakan waktu cukup lama).
Factoid keren
Dalam twist yang menarik, ada solusi BANYAK panjangnya 24, dan pemecah saya menemukan satu berbeda dari MT0, tetapi pada prinsipnya identik, kecuali bahwa itu dimulai dengan mengunjungi pos-pos lain yang terhubung 1. Menarik! Benar-benar melawan intuisi manusia, tetapi sangat valid.
Sorotan Solusi
Jadi ini milikku. Ini (sebagian) golf, b / c itu pemecah eksponensial, hampir kasar. Saya menggunakan algoritma IDDFS (iterative deepening depth first search), jadi ini adalah pemecah umum yang hebat yang tidak melewatkan, sehingga memecahkan kedua bagian dari pertanyaan OP, yaitu:
- Jika rute kemenangan ditemukan (zombie tanpa batas), hasilkan 'x'.
- Jika semua rute berakhir dengan kematian (zombie terbatas), hasilkan jumlah zombie terbanyak yang terbunuh.
Berikan kekuatan, ingatan, dan waktu yang cukup, dan itu akan melakukan hal itu, bahkan peta kematian lambat. Saya menghabiskan lebih banyak waktu untuk memperbaiki solver ini, dan sementara lebih banyak yang dapat dilakukan, itu sedikit lebih baik sekarang. Saya juga mengintegrasikan saran MT0 tentang solusi zombie tak terbatas terbaik, dan menghapus beberapa optimasi prematur dari win-checker saya yang mencegah versi sebelumnya menemukannya, dan sekarang saya sebenarnya menemukan solusi yang sangat mirip dengan yang dijelaskan oleh MT0.
Beberapa highlight lainnya:
- Seperti disebutkan, menggunakan IDDFS untuk menemukan rute kemenangan sesingkat mungkin.
- Karena itu adalah inti sebuah DFS, itu juga akan menemukan jika setiap rute berakhir dengan kematian pahlawan kita, dan melacak rute "terbaik" dalam hal sebagian besar zombie terbunuh. Mati pahlawan!
Saya telah memasukkan algoritme untuk membuatnya lebih menarik untuk ditonton Dihapus untuk tujuan bermain golf. Ikuti salah satu tautan ke github untuk melihat versi yang tidak diserang.
Ada sejumlah komentar juga, jadi jangan ragu untuk menerapkan kembali untuk solusi Anda sendiri berdasarkan pendekatan saya, atau tunjukkan padaku bagaimana itu harus dilakukan!
- Rute fast-forwarding memori-adaptif
- Hingga memori sistem yang tersedia, akan melacak "rute akhir" yang tidak mengakibatkan kematian.
- Dengan menggunakan rutin rute kompresi dan dekompresi, kemajuan dari iterasi IDDFS sebelumnya dipulihkan untuk mencegah penemuan kembali semua rute yang dikunjungi sebelumnya.
- Sebagai bonus sampingan yang disengaja, bertindak sebagai penyisihan rute jalan buntu. Rute jalan buntu tidak disimpan, dan tidak akan pernah dikunjungi lagi di kedalaman IDDFS mendatang.
Sejarah pemecah masalah
- Saya mencoba sekelompok algoritma satu langkah melihat-depan, dan sementara untuk skenario yang sangat sederhana mereka akan bekerja, akhirnya mereka gagal.
- Kemudian saya mencoba algoritma dua langkah melihat ke depan, yang .. tidak memuaskan.
- Saya kemudian mulai membangun lookahead n-step, ketika saya menyadari bahwa pendekatan ini dapat direduksi ke DFS, namun DFS jauh ... lebih elegan.
- Saat membangun DFS, terpikir oleh saya bahwa IDDFS akan memastikan (a) menemukan rute HERO (kematian) terbaik atau (b) siklus kemenangan pertama.
- Ternyata membangun win-cycle checker itu mudah, tetapi saya harus melalui beberapa iterasi yang sangat salah sebelum saya sampai ke checker yang terbukti berhasil.
- Dipertimbangkan dalam win-path MT0 untuk menghapus tiga baris optimasi prematur yang membuat algoritma saya buta untuk itu.
- Menambahkan algoritma caching rute adaptif yang akan menggunakan semua memori yang Anda berikan untuk mencegah pengerjaan ulang yang tidak perlu antara panggilan IDDFS, dan juga memilah rute buntu hingga batas memori.
Kode (golf)
Aktif ke kode (dapatkan versi yang tidak di -serigala di sini atau di sini ):
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);}}
Dapatkan kode dari github di sini, untuk melacak setiap perubahan yang saya buat. Berikut adalah beberapa peta lain yang saya gunakan.
Contoh keluaran
Contoh output untuk solusi referensi:
$ 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
Baca output rute seperti ini step:: source, route-to-get-here- ammo. Jadi dalam solusi di atas, Anda akan membacanya sebagai:
- Pada langkah
0, di pos terdepan 1dengan amunisi 100.
- Pada langkah
1, gunakan rute 1untuk mencapai pos 3dengan amunisi berakhir97
- Pada langkah
2, gunakan rute 1untuk mencapai pos 1dengan amunisi berakhir95
- ...
Catatan penutup
Jadi, saya harap saya membuat solusi saya lebih sulit untuk dikalahkan, tapi TOLONG MENCOBA! Gunakan untuk melawan saya, tambahkan beberapa pemrosesan paralel, teori grafik yang lebih baik, dll. Beberapa hal yang saya pikir dapat meningkatkan pendekatan ini :
- "kurangi" secara agresif loop untuk memotong ulang yang tidak perlu saat algoritme berlangsung.
- Contoh: dalam contoh masalah, pertimbangkan loop 1-2-3 dan permutasi lainnya sebagai "satu langkah", sehingga kita dapat membuat jalan kita untuk mengakhiri siklus lebih cepat.
- Misalnya, jika Anda berada di simpul 1, Anda dapat (a) pergi ke 2, (b) pergi ke 1, (c) melewati 1-2-3 sebagai satu langkah dan seterusnya. Ini akan memungkinkan penyelesaian untuk melipat kedalaman menjadi lebar, meningkatkan jumlah rute pada kedalaman tertentu tetapi sangat mempercepat waktu-untuk-solusi untuk siklus panjang.
menyisihkan rute mati. Solusi saya saat ini tidak "ingat" bahwa rute tertentu buntu, dan harus menemukan kembali setiap waktu. Akan lebih baik untuk melacak momen paling awal dalam rute yang kematiannya pasti, dan tidak pernah maju setelahnya. melakukan ini ...
- jika hati-hati, Anda bisa menerapkan culling rute mati sebagai cull sub-rute. Sebagai contoh, jika 1-2-3-4 selalu menghasilkan kematian, dan pemecah akan menguji rute 1-3-1-2-3-4, itu harus segera berhenti menuruni jalan itu karena dijamin akan berakhir dalam kekecewaan. Masih mungkin untuk menghitung jumlah pembunuhan, dengan perhitungan yang cermat.
Solusi lain yang memperdagangkan memori untuk waktu tertentu, atau memungkinkan penghindaran agresif mengikuti rute buntu. lakukan ini juga!
1mulai dengan 0 amunisi? Apakah grafiknya tidak langsung?