[编程题]纸牌博弈

题目描述:有一个整型数组A,代表数值不同的纸牌排成一条线。玩家a和玩家b依次拿走每张纸牌,规定玩家a先拿,玩家B后拿,但是每个玩家每次只能拿走最左或最右的纸牌,玩家a和玩家b都绝顶聪明,他们总会采用最优策略。请返回最后获胜者的分数。
给定纸牌序列A及序列的大小n,请返回最后分数较高者得分数(相同则返回任意一个分数)。保证A中的元素均小于等于1000。且A的大小小于等于300。
测试样例:

[1,2,100,4],4

返回:101

import java.util.Scanner;

public class Cards {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int n = scanner.nextInt();
            int[] A = new int[n];
            for (int i = 0; i < n; i++) {
                A[i] = scanner.nextInt();
            }
            System.out.println(cardGame(A, n));
        }
    }

    public static int cardGame(int[] A, int n) {
        // f[i][j]表示在牌[i...j]下,先选能获得的最大分数
        // s[i][j]表示在牌[i...j]下,后选能获得的最大分数
        int[][] f = new int[n][n];
        int[][] s = new int[n][n];
        for (int j = 0; j < n; j++) {
            f[j][j] = A[j];
            for (int i = j - 1; i >= 0; i--) {
                // 有两种拿法:1.先手拿最左边的。那么下一次拿的时候只能后选 2.先手拿最右边的。那么下一次拿的时候只能先选
                f[i][j] = Math.max(A[i] + s[i + 1][j], A[j] + s[i][j - 1]);
                s[i][j] = Math.min(f[i + 1][j], f[i][j - 1]); // 后手只能获得较小的分数
            }
        }
        return Math.max(f[0][n - 1], s[0][n - 1]);
    }
}

你可能感兴趣的:(经典算法面试题)