Play Game (博弈DP)

Play Game

HDU - 4597

Alice and Bob are playing a game. There are two piles of cards. There are N cards in each pile, and each card has a score. They take turns to pick up the top or bottom card from either pile, and the score of the card will be added to his total score. Alice and Bob are both clever enough, and will pick up cards to get as many scores as possible. Do you know how many scores can Alice get if he picks up first?

InputThe first line contains an integer T (T≤100), indicating the number of cases. 
Each case contains 3 lines. The first line is the N (N≤20). The second line contains N integer a i (1≤a i≤10000). The third line contains N integer b i (1≤bi≤10000).OutputFor each case, output an integer, indicating the most score Alice can get.

Sample Input

2 

1
23
53 

3
10 100 20
2 4 3 

Sample Output

53
105 题意:     Alice和Bob玩一个游戏,有两个长度为N的正整数数字序列,每次他们两个   只能从其中一个序列,选择两端中的一个拿走。他们都希望可以拿到尽量大   的数字之和,并且他们都足够聪明,每次都选择最优策略。Alice先选择,问   最终Alice拿到的数字总和是多少?题解:  dp[l1][r1][l2][r2]代表面对当前两个序列分别为l1~r1 l2~r2时,先手能拿到数字总和的最大值。而dp[l1][r1][l2][r2]是由dp[l1+1][r1][l2][r2],dp[l1][r1-1][l2][r2],dp[l1][r1][l2+1][r2],dp[l1][r1][l2][r2-1]四个状态转移来的。

这是第一个样例的dfs图

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int casen;
 7 int n;
 8 int dp[25][25][25][25];
 9 int sum1[30];
10 int sum2[30];
11 int dfs(int l1,int r1,int l2,int r2)
12 {
13     if(dp[l1][r1][l2][r2]!=-1)
14         return dp[l1][r1][l2][r2];
15     dp[l1][r1][l2][r2]=0;
16     int sum=sum1[r1]-sum1[l1-1]+sum2[r2]-sum2[l2-1];
17     if(l1<=r1)
18         dp[l1][r1][l2][r2]=max(dp[l1][r1][l2][r2],sum-dfs(l1+1,r1,l2,r2));
19     if(l1<=r1)
20         dp[l1][r1][l2][r2]=max(dp[l1][r1][l2][r2],sum-dfs(l1,r1-1,l2,r2));
21     if(l2<=r2)
22         dp[l1][r1][l2][r2]=max(dp[l1][r1][l2][r2],sum-dfs(l1,r1,l2+1,r2));
23     if(l2<=r2)
24         dp[l1][r1][l2][r2]=max(dp[l1][r1][l2][r2],sum-dfs(l1,r1,l2,r2-1));
25     return dp[l1][r1][l2][r2];
26 }
27 int main()
28 {
29     int x;
30     scanf("%d",&casen);
31     while(casen--)
32     {
33         memset(sum2,0,sizeof(sum2));
34         memset(sum1,0,sizeof(sum1));
35         memset(dp,-1,sizeof(dp));
36         scanf("%d",&n);
37         for(int i=1;i<=n;i++)
38         {
39             scanf("%d",&x);
40             sum1[i]=sum1[i-1]+x;
41         }
42         for(int i=1;i<=n;i++)
43         {
44             scanf("%d",&x);
45             sum2[i]=sum2[i-1]+x;
46         }
47         int ans=dfs(1,n,1,n);
48         printf("%d\n",dp[1][n][1][n]);
49     }
50 }


原文地址:https://www.cnblogs.com/1013star/p/10332191.html

时间: 2024-08-30 15:10:51

Play Game (博弈DP)的相关文章

UVA 1558 - Number Game(博弈dp)

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

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

UVa 10891 (博弈+DP) Game of Sum

最开始的时候思路就想错了,就不说错误的思路了. 因为这n个数的总和是一定的,所以在取数的时候不是让自己尽可能拿的最多,而是让对方尽量取得最少. 记忆化搜索: d(i, j)表示原序列中第i个元素到第j个元素构成的子序列,先手取数能够得到的最大值. sum(i, j) 表示从第i个元素到第j个元素的和 因为要让对手获得最小的分数,所以状态转移方程为: d(i, j) = sum(i, j) - min{d(枚举所有可能剩给对手的序列), 0(0代表全部取完)} s数组保存a中前i个元素的和,这样s

codeforcesB - A Lot of Games 博弈+dp

题意:给你n个字符串,给你一个序列,两个人轮流取一个字符使得现有的字符串是n个字符串里面的前缀,最后谁不能取谁就输掉这局,但是他们要玩K局,谁在K局赢了就等于赢了一整场比赛. 解题思路:字典树找是否有 必输 或者 必赢 的策略,如果同时有必赢或者必输的策略,那必定是first赢,如果只有必赢,那只需要讨论K奇偶,如果只有必输,那一定是second 解题代码: 1 // File Name: 1.cpp 2 // Author: darkdream 3 // Created Time: 2014年

codeforces 455B(博弈+dp)

题目链接: codeforces 455B 题目大意: 给出n个字符串,进行k次游戏,每次游戏输家下次作为先手,游戏规则为每次放一个字母,导致当前构造的字符串是给定的任意一个字符串的前缀,不能操作时为输,赢得第k次比赛的人会取得最终的胜利,问两人都采取最优策略的情况下,谁会赢得比赛. 题目分析: 首先针对这种字符串的问题我们很容易会想到利用字典树来解决,方便多模式匹配. 然后我们就能想到,这其实就是一个在树上的博弈,那么我们就可以通过dp知道先手是否有必胜策略和必败策略. 这个树上的博弈很基础,

hdu-4597 (博弈DP)

该题是用dp推导博弈题的经典例子 , 仔细想想就会发现,这其实就是一个区间处理的问题 ,一般区间问题还是比较简单的一类题目 . 由于两个孩子都很聪明,所以他们一定都尽可能的选择最优方案,所以每个人当前的最优解都依赖于下一个人的最优解 .    那么怎么处理细节呢 ? 还是老调重弹,先想状态如何表示,再想状态如何转移 . 很显然,要想完整的描述状态,我们必须开四维数组,记录两堆牌当前的状态 .  那么状态不难表示成  d[al][ar][bl][br] , 表示两堆牌当前的首尾情况下,所能获得的最

uvalive6913 I Want That Cake(博弈dp)

引自:http://www.cnblogs.com/qscqesze/p/5734143.html 题意: 有两支队,每只队都有n个人,一共有m个蛋糕,每个人至少吃一个,最多吃k个. 都采取最优策略,谁吃到最后一个蛋糕,那么那只队就胜利. 按照给定的顺序去吃蛋糕,问你最后谁胜利. 思路: 先缩点,把相同的点都缩成一个点. 那么就变成了ABABABA这样交替的形式了,然后跑DP就好了. dp[i][j]代表第i层代表的队伍蛋糕还剩j个时的状态 0为必败态,1为必胜态 首先,能把蛋糕吃完的状态为必胜

[博弈dp] hdu 4778 Gems Fight

给出g种颜色的宝石,然后有B个背包,S代表到时候每种颜色的宝石凑齐S个能变成一个魔法石 然后B行数输入,每个包里有哪些宝石 然后A,B轮流拿包,每个包只能拿一次,拿出包把宝石放地上. 如果能变成魔法石则拿走魔法石,下一次还这个人拿包,没变成则换人. 魔法石的个数就是获得分数,问两人最优的时候分差是多少. 思路: 只有21个包,状压dp. 然后发现不管顺序如何 最后构成的魔法石的个数是一定的. 然后在不同的二进制状态下,所剩在地面上的宝石是一定的. 那么就可以dp[i] 代表i这个状态下 先手取所

Codeforces 538E Demiurges Play Again(博弈DP)

http://codeforces.com/problemset/problem/538/E 题目大意: 给出一棵树,叶子节点上都有一个值,从1-m.有两个人交替从根选择道路,先手希望到达的叶子节点尽量大,后手希望到达的叶子节点尽量小,叶子节点的放置方案任意.两个人都足够聪明,能够得到的最大值和最小值分别是多少. 思路: 先考虑最大的情况 考虑dp[i]代表i这个节点能达到的最大的数字在这个子树中排第几. 如果当前是先手操作,那么他肯定会往最大的那个子树的方向走,即dp[u]=min(dp[v]