USACO Section 3.3 A Game pascal

描述 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>

点赞