lightoj 1031 Easy Game (区间dp 博弈)

来源:互联网 发布:小商店记账软件 编辑:程序博客网 时间:2024/04/30 10:54
 Easy Game
Time Limit: 2 second(s)     Memory Limit: 32 MB

You are playing a two player game. Initially there are n integer numbers in an array and player A and B get chance to take them alternatively. Each player can take one or more numbers from the left or right end of the array but cannot take from both ends at a time. He can take as many consecutive numbers as he wants during his time. The game ends when all numbers are taken from the array by the players. The point of each player is calculated by the summation of the numbers, which he has taken. Each player tries to achieve more points from other. If both players play optimally and player A starts the game then how much more point can player A get than player B?
Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case contains a blank line and an integer N (1 ≤ N ≤ 100) denoting the size of the array. The next line contains N space separated integers. You may assume that no number will contain more than 4 digits.
Output

For each test case, print the case number and the maximum difference that the first player obtained after playing this game optimally.

Sample Input

2
4
4 -10 -20 7
4
1 2 3 4
    
Output for Sample Input
Case 1: 7
Case 2: 10

题目链接:http://lightoj.com/volume_showproblem.php?problem=1031


题目大意:两个人从一堆数中取,每次只能从左边或者右边取,一次可以取任意多个,取得的数字的总和就是得分,问两人都采取最优策略的情况下,先手比后手最多多得多少分


题目分析:设dp[i][j]表示在当前状态下的先手比后手多得的最多分,然后进行区间dp,k将区间[i,j]分成[i,k]和(k,j]。
若当前这个人取的是左区间,则dp[i][j] = sum[k] - sum[i - 1] - dp[k + 1][j],注意这时候dp[k + 1][j]先前已经求出来了,假设现在是A取,他的前一个状态是B取,那么在(k,j]这里,B相当于此时的先手,所以dp[k + 1][j]就是B比A多得的分数,而sum[k] - sum[i - 1]表示A取完多得的分数,减去B比A多的就是A比B相对多的分数;假设现在是B取,那么同理。
若当前这个人取的是右区间的则dp[i][j] = sum[j] - sum[k] - dp[i][k],道理和上面相同。
所以dp[i][j]取两者的最大值即可,由于最先取的是第一个人,所以dp[1][n]表示先手比后手多得的最多分。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int const MAX = 105;int n, num;int sum[MAX], dp[MAX][MAX];int main() {    int T;    scanf("%d", &T);    for(int ca = 1; ca <= T; ca ++) {        printf("Case %d: ", ca);        memset(dp, 0, sizeof(dp));        scanf("%d", &n);        for(int i = 1; i <= n; i ++) {            scanf("%d", &num);            dp[i][i] = num;            sum[i] = sum[i - 1] + num;        }        for(int l = 1; l <= n; l ++) {            for(int i = 1; i + l <= n; i ++) {                int j = i + l;                dp[i][j] = sum[j] - sum[i - 1];                for(int k = i; k < j; k ++) {                    dp[i][j] = max(dp[i][j], max((sum[j] - sum[k]) - dp[i][k], (sum[k] - sum[i - 1]) - dp[k + 1][j]));                }            }        }        printf("%d\n", dp[1][n]);    }}


0 0
原创粉丝点击