zoukankan      html  css  js  c++  java
  • 两人比赛先选后选谁获胜系列的动态规划问题

    1.分金子(奇虎360 2017春招真题)

    题目描述

    A、B两伙马贼意外地在一片沙漠中发现了一处金矿,双方都想独占金矿,但各自的实力都不足以吞下对方,

    经过谈判后,双方同意用一个公平的方式来处理这片金矿。

    处理的规则如下:他们把整个金矿分成n段,由A、B开始轮流从最左端或最右端占据一段,直到分完为止。 

    马贼A想提前知道他们能分到多少金子,因此请你帮忙计算他们最后各自拥有多少金子?(两伙马贼均会采取对己方有利的策略)

    解析:

    dp[i][j]表示[i, j]先选者获得的最大利益 offset[i][j]表示[i,  j]后选择获得的最大利益

    import java.util.Scanner;
    
    public class Main {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int T = scanner.nextInt();
            for (int t = 0; t < T; t++) {
                int n = scanner.nextInt();
                int[] arr = new int[n];
                for (int i = 0; i < n; i++) {
                    arr[i] = scanner.nextInt();
                }
                solve(arr, t);
            }
        }
        public static void solve(int[] arr, int index) {
            int n = arr.length;
            int[][] dp = new int[n][n]; // dp[i][j]表示[i, j]先选者获得的最大
            int[][] offset = new int[n][n]; // offset[i][j]表示[i, j]后选择获得的最大
            for (int i = 0; i < n; i++) {
                dp[i][i] = arr[i];
            }
            for (int k = 1; k < n; k++) {
                for (int i = 0; i + k < n; i++) {
                    int j = i + k;
                    int left = arr[i] + offset[i + 1][j];
                    int right = arr[j] + offset[i][j - 1];
                    if (left >= right) {
                        dp[i][j] = left;
                        offset[i][j] = dp[i + 1][j];
                    } else {
                        dp[i][j] = right;
                        offset[i][j] = dp[i][j - 1];
                    }
                }
            }
            System.out.println("Case #" + (index + 1) + ": " +  dp[0][n - 1] + " " + offset[0][n - 1]);
        }
    }
    View Code

    2. Predict the Winner

    Given an array of scores that are non-negative integers. Player 1 picks one of the numbers from either end of the array followed by the player 2 and then player 1 and so on. Each time a player picks a number, that number will not be available for the next player. This continues until all the scores have been chosen. The player with the maximum score wins.

    Given an array of scores, predict whether player 1 is the winner. You can assume each player plays to maximize his score.

    解析:和第一题基本一样,最后比较dp[0][n - 1]和offset[0][n - 1]的大小即可。

    public boolean PredictTheWinner(int[] nums) {
            if (nums == null || nums.length < 3) {
                return true;
            }
            int n = nums.length;
            int[][] dp = new int[n][n]; // dp[i][j]表示[i, j]的先选者获得的最大
            int[][] offset = new int[n][n]; // offset[i][j]表示[i,j]的后选着获得的最大
            for (int i = 0; i < n; i++) {
                dp[i][i] = nums[i];
            }
            for (int k = 1; k < n; k++) {
                for (int i = 0; i + k < n; i++) {
                    int j = i + k;
                    int left = offset[i + 1][j] + nums[i];
                    int right = offset[i][j - 1] + nums[j];
                    if (left >= right) {
                        dp[i][j] = left;
                        offset[i][j] = dp[i + 1][j];
                    } else {
                        dp[i][j] = right;
                        offset[i][j] = dp[i][j - 1];
                    }
                }
            }
            return dp[0][n - 1] >= offset[0][n - 1];
        }
    View Code

    3.Can I Win

    In the "100 game," two players take turns adding, to a running total, any integer from 1..10. The player who first causes the running total to reach or exceed 100 wins.

    What if we change the game so that players cannot re-use integers?

    For example, two players might take turns drawing from a common pool of numbers of 1..15 without replacement until they reach a total >= 100.

    Given an integer maxChoosableInteger and another integer desiredTotal, determine if the first player to move can force a win, assuming both players play optimally.

    You can always assume that maxChoosableInteger will not be larger than 20 and desiredTotal will not be larger than 300.

    mask来记录我选择的时候面临的一个历史选择状态我会不会赢。然后choose记录已经被选择的。然后遍历深搜下去我可以选择的数。

    public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
            if (maxChoosableInteger >= desiredTotal) {
                return true;
            }
            if (maxChoosableInteger * (1 + maxChoosableInteger) / 2 < desiredTotal) {
                return false;
            }
            Boolean[] mask = new Boolean[1 << maxChoosableInteger];
            return help(maxChoosableInteger, desiredTotal, mask, 0, 0);
        }
        public boolean help(int max, int desire, Boolean[] mask, int sum, int choosed) {
            if (mask[choosed] != null) {
                return mask[choosed];
            }
            if (sum >= desire) {
                mask[choosed] = false;
                return false;
            }
            for (int i = 1; i <= max; i++) {
                int digit = 1 << (i - 1);
                if ((choosed & digit) == 0) {
                    choosed ^= digit;
                    boolean ulose = !help(max, desire, mask, sum + i, choosed);
                    choosed ^= digit;
                    if (ulose) {
                        mask[choosed] = true;
                        return true;
                    }
                }
            }
            mask[choosed] = false;
            return false;
        }
    View Code
  • 相关阅读:
    链表中环的入口节点
    链表中倒数第k个节点
    调整数组顺序使奇数位于偶数前面
    53. Maximum Subarray
    42. Trapping Rain Water
    48. Rotate Image
    css技巧一
    html语义
    label标签表单响应
    CSS清除浮动
  • 原文地址:https://www.cnblogs.com/futurehau/p/6646737.html
Copyright © 2011-2022 走看看