poj1678 I Love this Game!

 其他的已经加了注释,现在重点解析一下 dp[i] = num[i] - maxx;这句话的意义,首先dp[i]表示的是当前我取第i个,而下一个人取第j个数(num[j]>num[i])可以达到最优,那么为什么要取最大的dp[j]呢?
因为这样可以保证每次取得的策略最优,dp[j]是已经推得的sum(x[i])- sum(y[i])差距最大的值,那么对于当前我要加入这两堆的一个数num[i]来说当然是加入更大的一堆才能保证差值更大,但是因为我的num[i]固定加到一堆
(如 始终加到左堆),num[j]固定加到另一堆,那么就会出现num[i]反而加到了较小的一堆,如果出现这样的情况(其实必定都是这样的情况,因为我num[j]每次都会加入左堆,这就必然导致num[i]只能加到右堆),我只需要先将两堆交换位置,然后把num[i]加到左堆
因此dp[i] = num[i]-maxx;
举排序后的样例数据来说,
-3 -2 1 3 5 6
首先dp[5] = 6;
从后向前推,dp[4] = 5-6=-1;
意思就是我当前6放在右堆而5放在左堆,这样左堆-右堆可以达到一种情况-1,
然后3满足条件,可以进入左堆,那么最大的dp[j]也就是-1所对应的num[j]就应该进入右堆,但在之前的状态下5是在左堆那么dp[j] = 5-6=-1的
现在要想把差值扩大当然要想办法把5移入右堆,这样的话dp[i] = (6+3)-5 = 4才能达到差值更大,因此用num[i](3)-max(dp[j])=3-(5-6)=4就可以实现交换了。

大致我就是这么理解的,如果某位过路神牛发现了什么问题就留言告诉我下,小弟感激不尽。。。

 

#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 = 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;   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值