Java ( ít kỳ cục: 8415 5291 3301)
Được. Về cơ bản, tôi xấu hổ không ai gửi giải pháp. Vì vậy, một vài ngày trước tôi đã bắt đầu cố gắng giải quyết vấn đề này, vì nó thật tuyệt. . Theo liên kết đó để xem tiến trình của tôi về nó thông qua GitHub.
Chỉnh sửa
Phiên bản bộ giải mới, "đánh gôn" hơn nhiều, với trình kiểm tra chu kỳ đã sửa được xác định bởi MT0. Nó cũng hỗ trợ các tuyến chuyển tiếp nhanh, có thể điều chỉnh bằng cách thay đổi dung lượng bộ nhớ có sẵn cho VM. Chỉnh sửa BIG mới nhất : nhận ra rằng tôi có một vài lỗi chỉ số nhỏ khác và tối ưu hóa sớm, điều đó dẫn đến việc không xem xét khá nhiều loại chiến thắng. Vì vậy, đó là cố định, cẩn thận. Phiên bản mới nhỏ hơn và nhỏ hơn. Đối với tuyến đường tham chiếu của chúng tôi, java -Xmx2GB ZombieHordeMinthủ thuật này khá độc đáo (được cảnh báo, sẽ mất một lúc).
Thực tế mát mẻ
Trong một vòng xoắn hấp dẫn, có NHIỀU giải pháp ở độ dài 24 và người giải quyết của tôi tìm thấy một giải pháp khác với MT0, nhưng về nguyên tắc giống hệt nhau, ngoại trừ việc nó bắt đầu bằng cách truy cập các tiền đồn khác được kết nối 1. Hấp dẫn! Hoàn toàn chống lại trực giác của con người, nhưng hoàn toàn hợp lệ.
Giải pháp nổi bật
Vậy đây là của tôi. Đó là (một phần) được đánh gôn, vì nó là một người giải quyết theo cấp số nhân, gần như vũ phu. Tôi sử dụng thuật toán IDDFS (tìm kiếm đầu tiên chuyên sâu sâu lặp đi lặp lại), vì vậy đây là một trình giải tổng quát tuyệt vời không bỏ qua, vì vậy nó giải quyết cả hai phần của câu hỏi của OP, cụ thể là:
- Nếu một tuyến đường chiến thắng được tìm thấy (zombie vô hạn), hãy xuất 'x'.
- Nếu tất cả các tuyến kết thúc bằng cái chết (zombie hữu hạn), hãy xuất ra số lượng zombie lớn nhất bị giết.
Cung cấp cho nó đủ sức mạnh, bộ nhớ và thời gian, và nó sẽ làm được điều đó, thậm chí cả những bản đồ chết chậm. Tôi đã dành nhiều thời gian hơn để cải thiện bộ giải này, và trong khi có thể làm được nhiều hơn, bây giờ nó đã tốt hơn một chút. Tôi cũng đã tích hợp lời khuyên của MT0 về giải pháp zombie vô hạn tốt nhất và đã loại bỏ một số tối ưu hóa sớm khỏi trình kiểm tra win của tôi để ngăn phiên bản trước tìm thấy nó và thực tế bây giờ tôi tìm thấy một giải pháp rất giống với MT0 được mô tả.
Một vài điểm nổi bật khác:
- Như đã đề cập, sử dụng IDDFS để tìm ra con đường chiến thắng ngắn nhất có thể.
- Vì nó là cốt lõi của một DFS, nên nó cũng sẽ khám phá nếu mọi tuyến đường kết thúc bằng cái chết của anh hùng của chúng ta và theo dõi tuyến đường "tốt nhất" trong điều kiện hầu hết zombie bị giết. Chết một anh hùng!
Tôi đã sử dụng thuật toán để làm cho nó thú vị hơn khi xem Loại bỏ cho mục đích chơi gôn. Theo một trong các liên kết đến github để xem phiên bản chưa được chỉnh sửa.
Cũng có một số ý kiến, vì vậy hãy thoải mái triển khai lại để xây dựng giải pháp của riêng bạn theo cách tiếp cận của tôi, hoặc chỉ cho tôi cách thực hiện!
- Chuyển tiếp nhanh bộ nhớ thích ứng
- Lên đến bộ nhớ hệ thống khả dụng, sẽ theo dõi "các tuyến cuối" không dẫn đến tử vong.
- Sử dụng thói quen nén và giải nén tuyến ưa thích, tiến trình từ lần lặp trước của IDDFS được khôi phục để ngăn chặn việc khám phá lại tất cả các tuyến đã truy cập trước đó.
- Là một phần thưởng phụ có chủ ý, hoạt động như một con đường chết chóc. Các tuyến đường cụt không được lưu trữ và sẽ không bao giờ được truy cập lại ở độ sâu tương lai của IDDFS.
Lịch sử của người giải
- Tôi đã thử một loạt các thuật toán nhìn về phía trước một bước, và trong khi đối với các kịch bản rất đơn giản, chúng sẽ hoạt động, cuối cùng chúng bị xẹp.
- Sau đó, tôi đã thử một thuật toán nhìn về phía trước hai bước, đó là .. không thỏa mãn.
- Sau đó tôi bắt đầu xây dựng một cái nhìn n bước, khi tôi nhận ra rằng phương pháp này có thể rút gọn thành DFS, nhưng DFS thì ... thanh lịch hơn nhiều.
- Trong khi xây dựng DFS, đối với tôi, IDDFS sẽ đảm bảo (a) tìm ra tuyến HERO (cái chết) tốt nhất hoặc (b) chu kỳ chiến thắng đầu tiên.
- Hóa ra việc xây dựng một trình kiểm tra chu kỳ thắng là dễ dàng, nhưng tôi đã phải trải qua một vài lần lặp rất sai trước khi tôi có được một trình kiểm tra thành công có thể chứng minh được.
- Yếu tố trong đường dẫn chiến thắng của MT0 để loại bỏ ba dòng tối ưu hóa sớm khiến thuật toán của tôi bị mù với nó.
- Đã thêm một thuật toán lưu trữ tuyến đường thích ứng sẽ sử dụng tất cả bộ nhớ mà bạn cung cấp để ngăn chặn việc làm lại không cần thiết giữa các cuộc gọi IDDFS, đồng thời loại bỏ các tuyến đường cụt đến giới hạn của bộ nhớ.
Mã (được đánh gôn)
Bật mã (lấy phiên bản không được mã hóa ở đây hoặc ở đây ):
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);}}
Lấy mã từ github tại đây, để theo dõi bất kỳ thay đổi nào tôi thực hiện. Dưới đây là một số bản đồ khác tôi đã sử dụng.
Ví dụ đầu ra
Ví dụ đầu ra cho giải pháp tham chiếu:
$ 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
Đọc đầu ra tuyến đường như thế này step:: source, route-to-get-here- ammo. Vì vậy, trong giải pháp trên, bạn sẽ đọc nó như sau:
- Ở bước
0, tại tiền đồn 1với đạn 100.
- Tại bước
1, sử dụng tuyến đường 1để đi đến tiền đồn 3với đạn kết thúc97
- Tại bước
2, sử dụng tuyến đường 1để đi đến tiền đồn 1với đạn kết thúc95
- ...
Ghi chú kết thúc
Vì vậy, tôi hy vọng tôi đã làm cho giải pháp của mình khó bị đánh bại hơn, nhưng HÃY THỬ! Sử dụng nó để chống lại tôi, thêm vào một số xử lý song song, lý thuyết đồ thị tốt hơn, v.v ... Một vài điều tôi hình dung có thể cải thiện phương pháp này :
- tích cực "giảm" các vòng lặp để cắt bỏ việc đọc lại không cần thiết khi thuật toán tiến triển.
- Một ví dụ: trong bài toán ví dụ, hãy xem xét các vòng lặp 1-2-3 và các hoán vị khác là "một bước", để chúng ta có thể thực hiện theo cách kết thúc chu kỳ nhanh hơn.
- Ví dụ: nếu bạn ở nút 1, bạn có thể (a) đi đến 2, (b) đi đến 1, (c) đi qua 1-2-3 như một bước và cứ thế. Điều này sẽ cho phép giải quyết để gấp độ sâu thành chiều rộng, tăng số lượng tuyến đường ở độ sâu cụ thể nhưng tăng tốc đáng kể thời gian để giải pháp cho các chu kỳ dài.
loại bỏ các tuyến đường chết. Giải pháp hiện tại của tôi không "nhớ" rằng một tuyến đường cụ thể đã hết hạn và phải khám phá lại nó mỗi lần. Sẽ tốt hơn nếu theo dõi khoảnh khắc sớm nhất trong một lộ trình mà cái chết là chắc chắn, và không bao giờ tiến xa hơn nó. đã làm điều này ...
- nếu cẩn thận, bạn có thể áp dụng loại bỏ tuyến đường chết dưới dạng loại bỏ tuyến phụ. Ví dụ: nếu 1-2-3-4 luôn dẫn đến tử vong và người giải quyết kiểm tra tuyến 1-3-1-2-3-4, thì nó sẽ ngay lập tức dừng xuống đường đó vì nó được bảo đảm kết thúc trong thất vọng. Vẫn có thể tính được số lần giết, với một số phép toán cẩn thận.
Bất kỳ giải pháp nào khác trao đổi bộ nhớ theo thời gian hoặc cho phép tránh mạnh mẽ theo các tuyến đường cụt. cũng đã làm điều này
1bắt đầu với 0 đạn? Là đồ thị vô hướng?