รอบชิงชนะเลิศยืน - ความพ่ายแพ้ของฝูงชนผีดิบ


25

บทนำ

คุณเป็นคนเดียวบนเกาะ ส่วนที่เหลือของมนุษย์จะตาย ( อาจเป็นเพราะข้อผิดพลาดในรหัส user12345 ฯ ) ผีดิบโจรสลัด Horde ได้ถึงเกาะของคุณและพวกเขาจะไม่มีที่สิ้นสุด มันถึงเวลาที่จะเตะตูดหรือเคี้ยวหมากฝรั่งและคุณทุกเหงือก outta ฟอง

ปัญหา

สถานการณ์วันโลกาวินาศของเราคือการอธิบายโดย 2 จำนวนเต็มในบรรทัดเดียวและm nบนเกาะของคุณจะถูกนายทวารหมายเลขที่ไม่ซ้ำกันจาก 1 mถึง ต่อไปนี้nสายประกอบด้วยแต่ละสามจำนวนเต็มx, yและzคั่นด้วยช่องว่าง xและyเป็นหมายเลขที่ไม่ซ้ำกันของทั้งสองนายทวารและzเป็นจำนวนของซอมบี้ที่จะพบบนเส้นทางระหว่างพวกเขา

เมื่อคุณเดินทางไปตามทางคุณจะเสียzกระสุนและฆ่าzซอมบี้ หากคุณเดินทางไปในเส้นทางเดียวกันอีกครั้งคุณจะพบกับซอมบี้จำนวนเท่ากันอย่างน่าเสียดาย ด่านหน้าทั้งหมดสร้างกระสุน +1 ในแต่ละครั้งที่คุณเดินทาง คุณเริ่มต้นด้วยกระสุน 100 นัดที่ด่านหน้า 1 ด่านหน้าทั้งหมดเริ่มต้นด้วยกระสุน 0 นัด คุณตายทันทีหากไม่มีเส้นทางที่กระสุนของคุณมีจำนวนมากกว่าซอมบี้ในเส้นทางนั้นและกระสุนที่เหลือจะถูกแปลงเป็นสังหาร ดังกล่าวเป็นครั้งสุดท้ายของคุณ

เขียนโปรแกรมที่ให้จำนวนซอมบี้สูงสุดที่คุณสามารถฆ่าในสถานการณ์ที่กำหนด xหากคุณสามารถฆ่าจำนวนอนันต์ของซอมบี้ออกเพียง

ตัวอย่างการป้อนข้อมูล

5 6
1 2 4
2 3 4
3 1 4
2 4 10
2 5 10
1 1 50

ตัวอย่างผลลัพธ์

x

สมมติฐาน

  • เส้นทางจะอยู่ระหว่างสองด่านที่ถูกต้อง กล่าวคือ 1 <= x/ y<=m
  • หากเส้นทางระหว่างxและyไม่อยู่ในรายการจะไม่สามารถเดินทางได้
  • เส้นทางเป็นแบบสองทิศทาง
  • 1 m<<= 100
  • 1 n<<= 500
  • การป้อนข้อมูลจะต้องให้ผ่าน stdin อ่านจากไฟล์หรือได้รับการยอมรับเป็นอาร์กิวเมนต์ แต่เพียงผู้เดียวในการเขียนโปรแกรมและมันว่าต้องเป็นไปตามรูปแบบของตัวอย่างที่
  • รันไทม์ของโปรแกรมของคุณอาจมีขนาดใหญ่โดยพลการ แต่ต้องมีขอบเขตแน่นอน

รหัสที่มีตัวละครน้อยที่สุดชนะ!


แต่ละด่านอื่นที่ไม่ใช่1เริ่มต้นด้วย 0 ammo หรือไม่? กราฟเป็นแบบสองทิศทางหรือไม่?
Peter Taylor

2
มันอาจจะเป็นประโยชน์เช่นกันในการเตรียมคลาสของบั๊กล่วงหน้าโดยมีกรณีทดสอบซึ่งมีวัฏจักรที่ไม่ทำให้กระสุนของคุณหมดลง แต่ไม่สามารถเข้าถึงได้ทันเวลา (ฉันควรเพิ่มว่าฉันไม่มั่นใจว่ากรณีทดสอบปัจจุบันถูกต้อง: ดูเหมือนว่าฉันจะมี1->1ค่าใช้จ่าย 49 ammo และรอบ1->2->3->1ค่าใช้จ่าย 3 ammo ในระยะยาว
Peter Taylor

@PeterTaylor ผมต้องถอนทั้งความคิดเห็นของฉันเพราะมันดูเหมือนว่าฉันทำตัวอย่างแบบสองทิศทาง ดังนั้นให้ฉันเริ่มต้นใหม่ - เส้นทางทั้งหมดเป็นแบบสองทิศทางและด่านหน้าทั้งหมดเริ่มต้นด้วย 0 ตอนนี้ตัวอย่างควรใช้งานได้แล้ว
ฝนตก

@Rusher: ตัวอย่างที่ดี! ใช้เวลา 45 ขั้นตอนในการแสดงให้ฉันเห็นว่ามันยั่งยืนอย่างแท้จริง เราสามารถสันนิษฐานได้ว่าด่านหน้าทั้งหมดจะสามารถเข้าถึงได้หรือคุณต้องการให้เราจัดการกรณีที่มีด่านนอกตัดการเชื่อมต่อจากกราฟหลัก?
Claudiu

1
Ahhh ... ดังนั้นสำหรับแต่ละขั้นตอนจาก A ถึง B ทุกด่าน "สร้าง" กระสุนและเก็บไว้ที่นั่นจนกว่าคุณจะเยี่ยมชม
Tobia

คำตอบ:


14

Java ( ผิดปกติน้อยกว่า : 8415 5291 3301)

ตกลง. โดยพื้นฐานแล้วฉันอายที่ไม่มีใครส่งวิธีแก้ปัญหา เมื่อไม่กี่วันที่ผ่านมาฉันเริ่มพยายามแก้ปัญหานี้มันยอดเยี่ยมมาก . ติดตามลิงก์นั้นเพื่อดูความคืบหน้าของฉันผ่าน GitHub

แก้ไข

เวอร์ชั่นตัวแก้ปัญหาใหม่ "golfed" ที่มากขึ้นพร้อมตัวตรวจสอบรอบที่แก้ไขตามที่ระบุโดย MT0 นอกจากนี้ยังรองรับเส้นทางการส่งต่อที่รวดเร็วปรับแต่งได้โดยการเปลี่ยนจำนวนหน่วยความจำที่มีให้กับ VM ล่าสุดBIGแก้ไข: ตระหนักว่าผมมีข้อผิดพลาดเล็ก ๆ ไม่กี่ดัชนีและการเพิ่มประสิทธิภาพก่อนวัยอันควรที่ส่งผลให้เกิดความล้มเหลวในการพิจารณาค่อนข้างเป็นจำนวนมากของประเภทของผู้ชนะ นั่นคือการแก้ไขอย่างระมัดระวัง เวอร์ชันใหม่มีทั้งขนาดเล็กและด้านล่าง สำหรับเส้นทางอ้างอิงของเราjava -Xmx2GB ZombieHordeMinทำกลอุบายค่อนข้างดี (ได้รับคำเตือนมันจะใช้เวลาสักครู่)

เจ๋ง

ในการบิดที่น่าสนใจมีหลายโซลูชั่นที่มีความยาว 24 และแก้ของฉันพบหนึ่งที่แตกต่างจาก MT0 แต่ที่เหมือนกันในหลักการยกเว้นว่ามันเริ่มต้นโดยการเยี่ยมชมนายทวารอื่น ๆ 1ที่เชื่อมต่อกับ ที่น่าสนใจ! ทั้งหมดเคาน์เตอร์สัญชาตญาณของมนุษย์ แต่ที่ถูกต้องสมบูรณ์

โซลูชั่นไฮไลท์

ดังนั้นนี่คือเหมือง มันคือกอล์ฟบางส่วน, b / c เป็นตัวแก้ปัญหาแบบเลขชี้กำลัง, กำลังเกือบจะดุร้าย ฉันใช้อัลกอริทึม IDDFS (การค้นหาความลึกครั้งแรกซ้ำลึก) ซ้ำดังนั้นจึงเป็นนักแก้ปัญหาทั่วไปที่ยอดเยี่ยมที่ไม่ข้ามดังนั้นจึงสามารถแก้ปัญหาทั้งสองส่วนของคำถาม OP:

  • หากพบเส้นทางที่ชนะ (ซอมบี้ไม่มีที่สิ้นสุด) เอาท์พุท 'x'
  • หากเส้นทางทั้งหมดจบลงด้วยความตาย (ซอมบี้ที่ จำกัด ) ให้ฆ่าซอมบี้จำนวนมากที่สุด

ให้พลังความทรงจำและเวลาเพียงพอและจะทำเช่นนั้นแม้กระทั่งแผนที่ความตายช้า ฉันใช้เวลาในการปรับปรุงตัวแก้ปัญหานี้เพิ่มขึ้นและในขณะที่สามารถทำได้มากกว่านี้ ฉันยังได้รวมคำแนะนำของ MT0 ในการแก้ปัญหาซอมบี้อนันต์ที่ดีที่สุดและลบการปรับให้เหมาะสมก่อนกำหนดจำนวนมากออกจากตัวตรวจสอบของฉันที่ป้องกันเวอร์ชันก่อนหน้าจากการค้นหามันและตอนนี้ฉันจริง ๆ

ไฮไลท์อื่น ๆ :

  • ตามที่กล่าวไว้ใช้ IDDFS เพื่อค้นหาเส้นทางการชนะที่สั้นที่สุด
  • เนื่องจากเป็นแกนหลักของ DFS มันจะค้นพบว่าทุกเส้นทางจบลงด้วยการตายของฮีโร่ของเราและติดตามเส้นทาง "ดีที่สุด" ในแง่ของซอมบี้ที่ถูกฆ่าตาย ตายวีรบุรุษ!
  • ฉันได้นำอัลกอริทึมมาใช้เพื่อทำให้นาฬิกาน่าสนใจยิ่งขึ้นสำหรับการตีกอล์ฟ ติดตามลิงค์ใดลิงก์หนึ่งเพื่อไปยัง GitHub เพื่อดูเวอร์ชั่นที่ไม่ดี
  • มีความคิดเห็นจำนวนมากเช่นกันดังนั้นอย่าลังเลที่จะนำไปใช้ใหม่สำหรับโซลูชันของคุณในการสร้างแนวทางหรือแสดงให้ฉันเห็นว่าควรทำอย่างไร!
  • การส่งต่ออย่างรวดเร็วของหน่วยความจำที่ปรับเปลี่ยนได้
    • ถึงหน่วยความจำระบบที่มีอยู่จะติดตาม "เส้นทางปลายทาง" ที่ไม่ส่งผลให้เสียชีวิต
    • การใช้การบีบอัดเส้นทางแฟนซีและรูทีนการบีบอัดความคืบหน้าจากการวนซ้ำก่อนหน้าของ IDDFS จะถูกกู้คืนเพื่อป้องกันการค้นพบเส้นทางที่เยี่ยมชมก่อนหน้านี้ทั้งหมด
    • ในฐานะโบนัสด้านเจตนาทำหน้าที่เป็นตัวเลือกเส้นทางที่สิ้นตาย เส้นทางปลายทางไม่ถูกจัดเก็บและจะไม่ถูกเยี่ยมชมอีกครั้งในส่วนลึกของ IDDFS ในอนาคต

ประวัติความเป็นมาของนักแก้ปัญหา

  • ฉันลองใช้อัลกอริทึมการค้นหาล่วงหน้าแบบขั้นตอนเดียวและในขณะที่สำหรับสถานการณ์ที่ง่ายมาก ๆ พวกเขาจะทำงานในที่สุดพวกเขาก็ล้มเหลว
  • จากนั้นฉันลองอัลกอริธึมการค้นหาล่วงหน้าสองขั้นตอนซึ่ง .. ไม่พอใจ
  • จากนั้นฉันก็เริ่มสร้าง lookahead แบบขั้นตอนเดียวเมื่อฉันรู้ว่าวิธีนี้ลดทอนลงไปที่ DFS แต่ DFS นั้น ... สง่างามกว่ามาก
  • ในขณะที่สร้าง DFS เกิดขึ้นกับฉันที่ IDDFS จะทำให้แน่ใจว่า (a) ค้นหาเส้นทาง HERO (death) ที่ดีที่สุดหรือ (b) รอบการชนะครั้งแรก
  • กลายเป็นว่าการสร้างตัวตรวจสอบรอบชนะนั้นเป็นเรื่องง่าย แต่ฉันต้องผ่านการทำซ้ำหลาย ๆ ครั้งก่อนที่จะถึงตัวตรวจสอบที่ประสบความสำเร็จ
  • เอาไว้ใน win-path ของ MT0 เพื่อลบการเพิ่มประสิทธิภาพก่อนกำหนดสามบรรทัด
  • เพิ่มอัลกอริธึมการแคชเส้นทางที่ปรับได้ซึ่งจะใช้หน่วยความจำทั้งหมดที่คุณให้ไว้เพื่อป้องกันการทำซ้ำที่ไม่จำเป็นระหว่างการโทร IDDFS และยังกำจัดเส้นทางที่ปลายตายถึงขีด จำกัด ของหน่วยความจำ

รหัส (เล่นกอล์ฟ)

ไปที่รหัส (รับรุ่น ungolfed ที่นี่หรือที่นี่ ):

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ที่ด่านกับกระสุน1100
  • ในขั้นตอน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 มันควรจะหยุดลงจากเส้นทางนั้นทันทีเนื่องจากรับประกันว่าจะจบ ด้วยความผิดหวัง มันยังคงเป็นไปได้ที่จะคำนวณจำนวนการสังหารด้วยคณิตศาสตร์อย่างระมัดระวัง
  • โซลูชันอื่นใดที่ค้าขายหน่วยความจำเป็นระยะเวลาหรืออนุญาตการหลีกเลี่ยงเส้นทางที่ตามมาอย่างเด็ดขาด ทำเช่นนี้ด้วย!

คำตอบที่ดี! ใครต้องการรหัสของพวกเขาเมื่อพวกเขาเป็นคนเดียวที่สามารถแก้ปัญหาได้? ตอนนี้ฉันมีแรงบันดาลใจที่จะเขียนวิธีการแก้ปัญหาของตัวเองดังนั้นฉันจะทำงานต่อไป
Rainbolt

ยอดเยี่ยมนั่นคือสิ่งที่ฉันหวังว่าจะทำ รู้สึกอิสระที่จะยืม / ขโมยอะไรจากคำตอบของฉันที่คุณพบว่ามีประโยชน์! แม้ว่าแน่นอนฉันหวังว่าคนอื่น ๆ กว่าตัวเองและ OP จะพยายามแก้ปัญหา: P
ProgrammerDan

ฉันถูกปิดกั้นและเริ่มลดขนาดรหัสของคุณ หากคุณคิดว่าคำตอบของคุณผิดปกติก่อนที่จะตรวจสอบนี้: tny.cz/17ef0b3a ยังคงอยู่ระหว่างดำเนินการ
ฝนตก

ฮ่าฮ่าคุณได้รับนอกเส้นทางจริงๆ ดูดี (น่ากลัวพอสมควรสำหรับรหัส - กอล์ฟคุณรู้ว่าฉันหมายถึงอะไร) จนถึงตอนนี้!
ProgrammerDan

@Rusher โชคดีจนถึงตอนนี้? ฉันมีแนวคิดเล็กน้อยสำหรับการปรับปรุงที่ฉันได้ทำการต้มรวมถึงเทคนิคการบีบอัดข้อมูลการแทนเส้นทางและวิธีการส่งต่ออย่างรวดเร็วผ่านเส้นทางที่ประมวลผลแล้ว (จนถึงจุดหนึ่ง)
ProgrammerDan

2

บันทึกย่อบางส่วนเกี่ยวกับการแก้ปัญหา

ถ้าฉันได้เวลาฉันจะแปลงมันเป็นอัลกอริทึม ...

สำหรับกราฟที่ระบุมีกราฟGย่อยที่เชื่อมต่อG'ซึ่งมีเมือง1อยู่ หากมีวิธีการแก้ปัญหาไม่มีที่สิ้นสุดแล้วจะอยู่ที่เชื่อมต่อย่อยกราฟG''ของG'ที่มีVเมืองและPเส้นทาง

เส้นทางPของG''สามารถแบ่งพาร์ติชันดังกล่าวที่{p}มีเส้นทางซึ่งมีค่าใช้จ่ายน้อยที่สุดของเส้นทางทั้งหมดในPและP/{p}เป็นเส้นทางอื่น ๆ ทั้งหมด (ขึ้นรูปต้นไม้ทอดหรืออาจเป็นวงจร) หากเราสมมติว่าpไม่ใช่การวนรอบ (การเชื่อมต่อทั้งสองด้านเข้ากับเมืองเดียวกัน) จากนั้นมันจะเชื่อมต่อสองเมือง ( v1และv2) และมีcกระสุนราคาจากนั้นคุณ (ผู้รอดชีวิต) สามารถข้ามจากv1ไปv2และกลับด้วยค่า2cกระสุนทั้งหมด และสิ่งนี้จะเพิ่มปริมาณกระสุนในเมืองทั้งหมด 2 แห่ง (สำหรับการเพิ่มขึ้นทั้งหมด2|V|ภายในG''- บางแห่งจะถูกรวบรวมจากv1และv2)

หากคุณเดินทางจากv1ไปv2และกลับไปv1หลายครั้ง ( m) แล้วใช้เวลาเดินทางจากv1ตามขอบP/{p}เพื่อเยี่ยมชมเมืองทั้งหมดที่นอกเหนือจากv1และv2ก่อนที่จะกลับไปv1และสิ่งนี้ใช้nเส้นทางเพื่อให้บรรลุ (ซึ่ง|P/{p}| ≤ n ≤ 2|P/{p}|เนื่องจากคุณไม่จำเป็นต้องสำรวจเส้นทางเพิ่มเติม กว่าสองครั้งด้วยค่าใช้จ่ายkและเมืองจะได้รับ2m|V|กระสุน (อีกครั้งซึ่งบางส่วนจะถูกรวบรวมระหว่างการสำรวจเส้นทาง)

ให้ทั้งหมดนี้แล้วคุณสามารถบอกได้ว่าวิธีการแก้ปัญหาไม่มีที่สิ้นสุดเป็นไปได้ที่อาจเกิดขึ้นหากแล้วค่าใช้จ่ายเท่ากับหรือต่ำกว่าผลตอบแทนรวมk + 2mc2(m+n)|V|

มีความซับซ้อนเพิ่มเติมเกี่ยวกับปัญหาในการที่:

  • คุณอาจต้องเดินทางจากเมืองเริ่มต้น1ไปยัง{p}จุดแรกและต้องคำนึงถึงค่าใช้จ่ายนี้ และ
  • คุณต้องให้แน่ใจว่าmและnต่ำพอที่คุณจะไม่มีกระสุนเพียงพอก่อนที่คุณจะสามารถผ่านการทำซ้ำครั้งแรกได้เนื่องจากการทำซ้ำครั้งแรกจะมีค่าใช้จ่ายสูงกว่าการทำซ้ำครั้งต่อ ๆ ไป)

สิ่งนี้นำไปสู่ทางออกที่เป็นกลาง 24 เส้นทางสำหรับตัวอย่างในคำถาม (ตัวเลขคือเมืองที่เยี่ยมชม):

1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,2,4,2,5,2,3, ... and repeat ...

สิ่งเล็ก ๆ น้อย ๆ ที่ต้องเพิ่มอีกอย่างหนึ่ง - คุณอาจต้องพิจารณาถึงการวนรอบขอบด้วยต้นทุน 1 เนื่องจากขอบเหล่านั้นสร้างเงื่อนไขการชนะหากคุณสามารถเข้าถึงพวกเขาได้ทันเวลา
Rainbolt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.