poj 1678 I Love this Game!(博弈dp)


I Love this Game!

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 1892   Accepted: 723

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

Source

POJ Monthly--2004.06.27 [email protected]

题意:有N个数,有一个区间[A,B],第一个人先取一个数x(A<=x<=B),后一次取必须

比第一个数大,而且差值在区间内。问最后两个人取的数的和的差值最大为多少。

思路:dp[i]表示如果先手取了第i个数,可以达到的最大分差。那么最后一次取的分差就

是本身。dp[ i ] = a[ i ] - max(dp[ j ]) ( i < j )  , 其意义为第一个人取第 i 个后,然后就相当

第二个人现在变成了先手,即他要保证最大分差。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int inf=1<<30;
const int maxn=10010;

int dp[maxn],a[maxn],n,l,r;

void input()
{
    scanf("%d %d %d",&n,&l,&r);
    for(int i=0;i<n;i++)   scanf("%d",&a[i]);
    sort(a,a+n);
}

void initial()
{
    for(int i=0;i<n;i++)  dp[i]=-inf;
}

int DP(int x)
{
    if(dp[x]!=-inf)  return dp[x];
    int ans=-inf;
    for(int i=x+1;i<n;i++)
        if(a[i]-a[x]>=l && a[i]-a[x]<=r)
            ans=max(ans,DP(i));
    if(ans==-inf)  dp[x]=a[x];
    else  dp[x]=a[x]-ans;
    return dp[x];
}

void solve()
{
    int Max=-inf;
    for(int i=0;i<n;i++)
      if(a[i]>=l && a[i]<=r)
           Max=max(Max,DP(i));
    if(Max==-inf)  printf("0\n");
    else   printf("%d\n",Max);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        input();
        initial();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-01 10:12:05

poj 1678 I Love this Game!(博弈dp)的相关文章

POJ 2411 Mondriaan&#39;s Dream(状压DP)

http://poj.org/problem?id=2411 求一个n*m矩阵用1*2方块去填满的情况有几种 思路:状压dp,先预处理那些状态之间能互相到达,情况就几种,上一个两个1,下一个状态也两个1,上一个为0,下一个必须为1,还有一种是上一个为1,下一个为0的情况 然后就一层层往后递推即可 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int

TOJ 2294 POJ 3286 How many 0&#39;s? 数位dp

http://acm.tju.edu.cn/toj/showp2294.html http://poj.org/problem?id=3284 题外话:集训结束,回学校了.在宿舍看了这题,没什么好想法,去洗澡了.转了两个澡堂都特么没开..倒是在路上把这题想了.用回自己的电脑,不得不说苹果的字体渲染,真心高一个等级. 题意:给定两个数a和b,从a写到b,问一共写了多少个0. 分析:当然先转化为求0..a写多少个0.网上有更简单的做法,就是枚举每位作为0,则如果这一位本来是0,左边取1..a-1(不

POJ 3249 Test for Job 拓扑排序+DP

http://poj.org/problem?id=3249 题意: 给一个有向无环图DAG(不一定联通),每个点有权值,入度为0的点为起点,出度为0的点为终点,选择一个起点走到一个终点,使得路上的权和最大. 分析: dp[to] = max(dp[from]) + value[to],然后先拓扑排序保证状态正确转移即可,终点做标记,如果是终点则尝试更新答案. update:因为点权可以为负,所以程序里用dp[i] == -1表示未访问过该点是有问题的,不过没有遇上会卡掉这种情况的数据=.= 1

poj 3254 Corn Fields ,状态压缩DP

题目链接 题意: 一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案(一头牛都不放也是一种方案) state[i] 表示对于一行,保证不相邻的方案 状态:dp[i][ state[j] ]  在状态为state[j]时,到第i行符合条件的可以放牛的方案数 状态转移:dp[i][ state[j] ] =Sigma dp[i-1][state'] (state'为符合条

UVA 1558 - Number Game(博弈dp)

UVA 1558 - Number Game 题目链接 题意:20之内的数字,每次可以选一个数字,然后它的倍数,还有其他已选数的倍数组合的数都不能再选,谁先不能选数谁就输了,问赢的方法 思路:利用dp记忆化去求解,要输出方案就枚举第一步即可,状态转移过程中,选中一个数字,相应的变化写成一个函数,然后就是普通的博弈问题了,必胜态之后必有必败态,必败态之后全是必胜态 代码: #include <stdio.h> #include <string.h> const int N = 105

POJ 2411 Mondriaan&#39;s Dream ——状压DP 插头DP

[题目分析] 用1*2的牌铺满n*m的格子. 刚开始用到动规想写一个n*m*2^m,写了半天才知道会有重复的情况. So Sad. 然后想到数据范围这么小,爆搜好了.于是把每一种状态对应的转移都搜了出来. 加了点优(gou)化(pi),然后poj上1244ms垫底. 大概的方法就是考虑每一层横着放的情况,剩下的必须竖起来的情况到下一层取反即可. 然后看了 <插头DP-从入门到跳楼> 这篇博客,怒抄插头DP 然后16ms了,自己慢慢YY了一下,写出了风(gou)流(pi)倜(bu)傥(tong)

poj 2411 Mondriaan&#39;s Dream 状压dp入门

题意: 求h*w的矩形被1*2的小矩形覆盖的方案数. 分析: 状压dp入门,<挑战程序设计竞赛>上讲的很好,好几天才看懂. 代码: #include <iostream> using namespace std; __int64 ans[16][16]; int n,m; __int64 dp[2][1<<16]; __int64 solve() { int i,j,used; memset(dp,0,sizeof(dp)); __int64 *crt=dp[0],*n

UVA 1557 - Calendar Game(博弈dp)

UVA 1557 - Calendar Game 题目链接 题意:给定一个日期,两个人轮流走,每次可以走一月或者一天,问最后谁能走到2001.11.4这个日子 思路:记忆化搜索,对于每个日期,如果下两个状态有一个非必胜态,那么这个状态是必胜态,如果后继状态都是必胜态,那么该状态为必败态 代码: #include <stdio.h> #include <string.h> const int day[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31,

UVA 1559 - Nim(博弈dp)

UVA 1559 - Nim 题目链接 题意:一开始有s个石子,2n个人轮流取石子,每个人有个最大能取数目,2n个人奇数一队,偶数一队,取到最后一个石子的队输,问谁赢 思路:记忆化搜索,每个人取的时候对应的后继状态如果有一个必败态,则该状态为必胜态,如果都是必胜态,则该状态为必败态 代码: #include <stdio.h> #include <string.h> int n, s, m[25], dp[25][10005]; int dfs(int now, int state

POJ 3373 Changing Digits 好蛋疼的DP

一开始写的高位往低位递推,发现这样有些时候保证不了第四条要求.于是又开始写高位往低位的记忆化搜索,又发现传参什么的蛋疼的要死.然后又发现高位开始的记忆化搜索就是从低位往高位的递推呀,遂过之. dp[i][j]记录在i位 且 余数为j时的最优解情况. dp[i][j].next表示当前的最优解是由哪一种状态转移过来的. 代码又写锉了.. #include <algorithm> #include <iostream> #include <cstring> #include