PKU 1678 I Love this Game

I Love this Game!
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 1270   Accepted: 458

Description

A traditional game is played between two players on a pool of n numbers (not necessarily distinguishing ones). 

The first player will choose from the pool a number x1 lying in [a, b] (0 < a < b), which means a <= x1 <= b. Next the second player should choose a number y1 such that y1 - x1 lies in [a, b] (Attention! This implies y1 > x1 since a > 0). Then the first player should choose a number x2 such that x2 - y1 lies in [a, b]... The game ends when one of them cannot make a choice. Note that a player MUST NOT skip his turn. 

A player's score is determined by the numbers he has chose, by the way: 

player1score = x1 + x2 + ... 
player2score = y1 + y2 + ... 

If you are player1, what is the maximum score difference (player1score - player2score) you can get? It is assumed that player2 plays perfectly. 

Input

The first line contains a single integer t (1 <= t <= 20) indicating the number of test cases. Then follow the t cases. Each case contains exactly two lines. The first line contains three integers, n, a, b (2 <= n <= 10000, 0 < a < b <= 100); the second line contains n integers, the numbers in the pool, any of which lies in [-9999, 9999].

Output

For each case, print the maximum score difference player1 can get. Note that it can be a negative, which means player1 cannot win if player2 plays perfectly.

Sample Input

3
6 1 2
1 3 -2 5 -3 6
2 1 2
-2 -1
2 1 2
1 0

Sample Output

-3
0
1

/*
******************************************************************************************************
题目大意:有两个小盆友面对一堆数字,第一个小盆友取一个数字x1,x1满足0<a<=x1<=b,然后,两人轮流取数字,
保证与上个人的差值也在[a,b]中。问小盆友1取的数字和减去小盆友2取的数字和的差值最大是好多?求这个最大值。
******************************************************************************************************
现在看这题,小盆友1,总想差值尽可能的大,那么,小盆友2取了第i个数后,那么加上剩下的局面最大差值不就可以了?从这里,可以看出,这题其实是无后效性的。
那么在取第i个数时,小盆友肯定会很聪明滴选前面可取的最优局面来取撒。从这里,看出,是从最优推出最优。OK,动态规划。

题目给出0<a,如果我们将所有数字排序,很明显,两个小盆友在从前往后取数。

关于差值,对于小盆友1来说,是把他取的数加到这个差值中,而对于小盆友2来说,是把他取的数从差值中减去。这里,感觉还是比较纠结。
我们观察:
a-b
c-(a-b)=c-a+b
d-(c-a+b)=d-c+a-b
e-(d-c+a-b)=e-d+c-a+b
……
观察,对于每个式子而言,正号的可以看成是小盆友1所取的数,负号的可以看成是小盆友2所取的数。如果,我们从后往前做,有:
dp[a]=a-b
dp[c]=c-a+b
dp[d]=d-c+a-b
dp[e]=e-d+c-a+b
……
那dp[i]存的就是从i开始,小盆友取位置i的数后最大差值。

所以,这题的解决办法就诞生了。
我们用dp[i]表示小盆友第一个取的数字是i位置的数字。
小盆友1必取第i位置上的数,这是我们的定义,小盆友2很聪明,他就不想让小盆友1取得最大值,
于是,小盆友2选择可取的j中dp[j]最大的一个,这样dp[i]就小盆友1从这里取的差值就小了。
既:dp[i]=a[i]-max{dp[j]}。
 */
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm> 
using namespace std;
int dp[11000];//dp[i]表示当前我取第i个数而下一个人取第j个数的最大结果 
int num[11000];
int n, a, b;
bool comp(int x)
{
     return (x >= a && x <= b);         
}
bool cmp(int a, int b)
{
     return a<b;     
}
int main()
{
    int t;
    scanf("%d", &t);
    while ( t --){
          scanf("%d%d%d", &n, &a, &b);
          for (int i = 0; i < n; i ++){
              scanf("%d", &num[i]);      
          }      
          sort(num, num+n, cmp);//排序之后可以优化查找过程 
          for (int i = 0; i < n; i ++)
              dp[i] = num[i];//一开始初始值为num[i],因为如果一开始就有符合要求的数,我肯定会取到 
          dp[n-1] = num[n-1];//根据DP的定义从后向前倒推 
          int maxx;
          for (int i = n-2; i >= 0; i --){//我当前取第num[i]个数 
              maxx = INT_MIN;
              for (int j = i+1; j < n; j ++){//根据我取得的num[i]来依次查找到最大的dp[j],因为两人都是按照最优的方法来找的,故会找到当前最大的差值,因为他们都要求自己取到的数导致最终结果尽可能的大 
                  if (comp(num[j]-num[i]) && maxx < dp[j]){
                     maxx = dp[j];
                  }    
                  if (num[j] - num[i] > b)break; 
              }    
              if (maxx != INT_MIN)
                 dp[i] = num[i] - maxx;//maxx为max{dp[j]}
          }
          maxx = INT_MIN;
          for (int i = 0; i < n; i ++){
              if (comp(num[i]) && maxx < dp[i])maxx = dp[i];
              if (num[i] > b)break;   
          }
          if (maxx == INT_MIN)maxx = 0;
          printf("%d\n", maxx);
    }  
    return 0;    
}
原文地址:https://www.cnblogs.com/qianmacao/p/2459050.html