爪哇(不那么怪异:8415 5291 3301)
好。基本上,我很尴尬,没有人提交解决方案。因此,几天前我开始尝试解决此问题,b / c很棒。。单击该链接以通过GitHub观看我的进度。
编辑
新的求解器版本,更加“实用”,具有MT0标识的更正循环检查器。它还支持快速转发路由,可通过更改VM可用的内存量来进行调整。最新的BIG编辑:意识到我还有其他一些小的索引错误和过早的优化,导致未能考虑很多类型的胜利。所以,这是固定的,请小心。新版本既小又小。对于我们的参考路线,java -Xmx2GB ZombieHordeMin技巧非常好(请注意,这将需要一段时间)。
酷的事实
令人着迷的是,许多解决方案的长度为24,而我的求解器发现了一个与MT0不同的解决方案,但在原理上相同,不同之处在于它从访问与相连的其他前哨站开始1。迷人!完全抵制人类的直觉,但完全有效。
解决方案要点
所以这是我的。它(部分)打了高尔夫球,b / c是一个指数的,几乎是蛮力的求解器。我使用IDDFS(迭代深入深度优先搜索)的算法,所以它不跳过一个伟大的一般解算器,所以它解决了两个任择议定书的问题,即部分:
- 如果找到获胜路线(无限僵尸),则输出“ x”。
- 如果所有路径都以死亡结尾(有限的僵尸),则输出被杀死的最大数量的僵尸。
给它足够的能力,内存和时间,它将做到这一点,甚至是慢死地图。我花了更多时间改进此求解器,尽管可以做更多的事情,但现在情况有所好转。我还将MT0的建议整合到了最佳的无限僵尸解决方案上,并从我的获胜者中删除了一些过早的优化,这些优化阻止了以前的版本无法找到它,现在我确实找到了与上述MT0非常相似的解决方案。
其他一些亮点:
- 如前所述,使用IDDFS查找最短的获胜路线。
- 由于它是DFS的核心,因此它还将发现每条路线是否以我们英雄的死亡而结束,并就大多数丧尸丧生而言跟踪“最佳”路线。死一个英雄!
我已经对该算法进行了测试,以使其更有趣地观看出于高尔夫目的而观看《已移除》。按照指向github的链接之一查看未发布的版本。
整个过程中也有很多评论,请随时根据我的方法重新实现您自己的解决方案,或者告诉我应该如何做!
- 内存自适应路由快速转发
- 直到可用的系统内存,都将跟踪未导致死亡的“结束路由”。
- 使用奇特的路由压缩和解压缩例程,可以恢复IDDFS先前迭代的进度,以防止重新发现所有先前访问的路由。
- 作为故意的附加奖励,充当死路路线的选择。死端路由不会存储,在IDDFS的未来深度中也不会再次访问。
求解器的历史
- 我尝试了一堆单步向前的算法,虽然对于非常简单的场景它们可以工作,但最终它们会变得平淡无奇。
- 然后,我尝试了两步式的前瞻算法,这是令人不满意的。
- 然后,当我意识到这种方法可以简化为DFS时,我便开始进行n步前瞻,但是DFS远不止于此……更优雅。
- 在构建DFS时,我想到IDDFS将确保(a)找到最佳的HERO(死亡)路线或(b)第一个获胜周期。
- 事实证明,构建一个胜利周期检查器很容易,但是在获得一个可以证明是成功的检查器之前,我不得不经历几次非常非常错误的迭代。
- 考虑到MT0的获胜路径,消除了三行过早的优化,这使我的算法无视了。
- 添加了自适应路由缓存算法,该算法将使用您提供的所有内存,以防止IDDFS调用之间不必要的工作重做,并且还将死端路由剔除到内存限制。
(行进的)代码
转到代码(在此处或在此处获取非高尔夫版本):
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);}}
从github获取代码,以跟踪我所做的任何更改。这是我使用过的其他一些地图。
输出例子
参考解决方案的示例输出:
$ 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
读取路由输出,如下所示step::source,route-to-get-here- ammo。因此,在上述解决方案中,您将其读取为:
- 在步枪
0,在前哨1与弹药100。
- 在步骤中
1,使用路线1以3终点弹药到达前哨站97
- 在步骤中
2,使用路线1以1终点弹药到达前哨站95
- ...
结束语
因此,我希望我的解决方案更难被击败,但是请尝试!对我使用它,添加一些并行处理,更好的图论,等等。我认为有几点可以改进这种方法:
- 随着算法的发展,积极地“减少”循环以消除不必要的重读。
- 一个示例:在示例问题中,将循环1-2-3和其他排列视为“一步”,以便我们可以更快地结束循环。
- 例如,如果您在节点1上,则可以(a)转到2,(b)转到1,(c)第一步经过1-2-3,依此类推。这将使解决方案能够将深度折叠成宽度,增加特定深度处的路线数量,但可以大大加快长周期的求解时间。
剔除死路。我当前的解决方案不能“记住”某条路线是死路一条,而每次都必须重新发现它。最好在确定死亡的路线上尽早追踪,并且永远不要超越死亡。做过这个...
- 如果谨慎,可以将死路线剔除应用为子路线剔除。例如,如果1-2-3-4总是会导致死亡,而求解器将要测试路径1-3-1-2-3-4,则它应立即停止沿该路径下降,因为这样可以保证结束感到失望 通过一些仔细的数学运算,仍然有可能计算出击杀次数。
任何其他将内存换为时间的解决方案,或允许积极避免遵循死胡同路线的解决方案。也做到了!
1以0的弹药开始以外,每个前哨基地是否都存在?图是无方向的吗?