描述 Description
有如下一个双人游戏:N(2 <= N <= 100)个正整数的序列放在一个游戏平台上,两人轮流从序列的两端取数,取数后该数字被去掉并累加到本玩家的得分中,当数取尽时,游戏结束。以最终得分多者为胜。
编一个执行最优策略的程序,最优策略就是使自己能得到在当前情况下最大的可能的总分的策略。你的程序要始终为第二位玩家执行最优策略。
输入格式 Input Format
第一行: 正整数N, 表示序列中正整数的个数。
第二行至末尾: 用空格分隔的N个正整数(大小为1-200)。
输出格式 Output Format
只有一行,用空格分隔的两个整数: 依次为玩家一和玩家二最终的得分。
这是个双人博弈问题。博弈的最优策略是使对方获利最小的情况下使自己获利最大(“最坏最好”),在搜索中著名的alpha-beta搜索就是针对这种情况:这种博弈假设对手是总是采用最优策略(也就是:遇到“最坏”的对手),而在这种情况下,选择一个行动使得对手的获利最小,即为自身的最优策略。从而,很容易的得到此题的动态规划方程:
设sum(s,t)为区间s,t中的数字之和,gain(s,t)为按最优策略能获得的最大得分,那么,有两种数字的方式,
1.取s,则给对手余下区间(s+1,t),对手的收益将是gain(s+1,t);
2.或者取t,则给对手留下区间(s,t-1),对手的收益将是gain(s,t-1);
无论如何,自身得分是sum(s,t)-对手得分,从而:
gain(s,t)=sum(s,t)-min{gain(s+1,t),gain(s,t-1)}.
3.我看过一种动态规划的方法叫自顶向下的备忘录方法,这题恰好可以用
经过测试数据,如果仅仅是搜索的话n= 30已经开始以秒为单位计时,按照指数倍数相乘n= 40你可以去等几小时几天了,不理解或者需要交流的同学可以粉我新浪微博@雷锹,私信哟!!!回复速度是很快的,鄙人比较喜欢玩这个
<span style="color:#000000;">package com.lanqiaobei.nosource;
import java.util.Scanner;
public class _20 {
public static int sum[][];
public static int memorize[][];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int array[] = new int [n+1];
sum = new int [n+1][n+1];
memorize = new int [n+1][n+1];
for(int i = 1; i <= n; i++){
array[i] = scan.nextInt();
}
for(int i = 1; i <= n; i++)
for(int j = i; j <= n; j++){
sum[i][j] = sum[i][j-1] + array[j];
}
System.out.println(memorize_gain(array,1,n) + " " + (sum[1][n]-memorize[1][n]));
}
private static int memorize_gain(int[] array,int i,int j) {
// TODO Auto-generated method stub
if(i == j){
memorize[i][j] = array[i];
return array[i];
}
int p,q;
if(memorize[i+1][j] > 0){
p = memorize[i+1][j];
}else{
p = memorize_gain(array, i+1, j);
}
if(memorize[i][j-1] > 0){
q = memorize[i][j-1];
}else{
q = memorize_gain(array, i, j-1);
}
memorize[i][j] = sum[i][j] - Math.min(p,q);
return memorize[i][j];
}
}
</span>