博弈論之雙人取數遊戲詳解
阿新 • • 發佈:2019-01-08
描述
有如下一個雙人遊戲:N(2 <= N <= 100)個正整數的序列放在一個遊戲平臺上,遊戲由玩家1開始,兩人輪流從序列的兩端取數,取數後該數字被去掉並累加到本玩家的得分中,當數取盡時,遊戲結束。以最終得分多者為勝。
編一個執行最優策略的程式,最優策略就是使玩家在與最好的對手對弈時,能得到的在當前情況下最大的可能的總分的策略。你的程式要始終為第二位玩家執行最優策略。
格式
PROGRAM NAME: game1
INPUT FORMAT:
(file game1.in)
第一行: 正整數N, 表示序列中正整數的個數。
第二行至末尾: 用空格分隔的N個正整數(大小為1-200)。
OUTPUT FORMAT
(file game1.out)
只有一行,用空格分隔的兩個整數: 依次為玩家一和玩家二最終的得分。
SAMPLE INPUT
6 4 7 2 9 5 2
SAMPLE OUTPUT
18 11
思路:用遞迴會看起來清晰一點,定義一個dfs方法,返回如果取區間ns第i到第j個數時的最大值。
這裡我就單純遞迴,可以自己加一個記憶陣列提高效率
public class 雙端取求遊戲 { static int[][] sum = new int[1000][1000];//儲存ns內的各區間和,sum[0][3]表示第0到第3個數的和 static int[] ns = new int[]{4,7,2,9,5,2};//能取的數 /*用處: 得到ns區間中第i到j個數先手能拿到的最大值 */ static int dfs(int i,int j){ if (i==j) {//如果只有一個數,返回他本身 return ns[i]; } if (Math.abs(i-j)==1) {//如果是兩個數的局面,先手的取那個大的就行了 return Math.max(ns[i],ns[j]); } /* 大於兩個數的局面,先手試探取首數和尾數後把子局面扔給下一個人,從兩個子局面中挑一個分數大的 sum[i+1][j] - dfs(i+1, j)+ns[i] 是取完左邊的數後能獲得的最大值 sum[i][j-1] - dfs(i, j-1)+ns[j] 是取完右邊的數後能獲得的最大值 先手把子局面交給後手後,先手得到的分應該是區間總和-子局面中先手獲得的分+取的首數或尾數 */ return Math.max(sum[i+1][j] - dfs(i+1, j)+ns[i], sum[i][j-1] - dfs(i, j-1)+ns[j]); } //初始化sum陣列 static void initSum(){ for (int i = 0; i < ns.length; i++) { int tmp = 0; for (int j = i; j < ns.length; j++) { tmp += ns[j]; sum[i][j] = tmp; } } } public static void main(String[] args) { initSum(); System.out.println(dfs(0, 5)+" " + (sum[0][5]-dfs(0, 5))); } }