• 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;    
    }
  • 相关阅读:
    Java中Class.forName()用法和newInstance()方法详解
    开发和学习中好用的工具
    ubuntu修改默认的apt源
    区块链共识算法总结(PBFT,Raft,PoW,PoS,DPoS,Ripple)
    比特币白皮书:一个点对点的电子现金系统(百度网盘)
    session和cookie的区别
    HTTP中GET,POST和PUT的区别
    三小时快速入门Python终结篇--其他模块导入
    C/C++ 多继承{虚基类,虚继承,构造顺序,析构顺序}
    C++ 实现vector<std:string> 版本
  • 原文地址:https://www.cnblogs.com/qianmacao/p/2459050.html
Copyright © 2020-2023  润新知