博弈dp入门 POJ - 1678 HDU - 4597
本来博弈还没怎么搞懂,又和dp搞上了,哇,这真是冰火两重天,爽哉妙哉。
我自己的理解就是,博弈dp有点像对抗搜索的意思,但并不是对抗搜索,因为它是像博弈一样,大多数以当前的操作者来dp,光想是想不通的,上题练一练。
POJ - 1678 I Love this Game!
题目大意:有两个人正在玩游戏,在给出的一堆数中,玩家1先在[a,b]的范围中挑选出一个x1,然后玩家2再挑选有个y1满足a≤y1-x1≤b,然后玩家1再挑选一个x2满足a≤x2-y1≤b,以此轮流操作,直到某个玩家不能再进行操作,此时玩家1的分值为x1+x2+...,玩家2的分值为y1+y2+...,两个玩家都足够聪明,求最大的分差是多少?
其实不管就算是在博弈里,我觉得最难理解的也就是那句都足够聪明(我不够聪明怎么办),然后就在想如果足够聪明接下来会怎么做,然后推推推半天又不确定自己模拟的是不是就是都足够聪明下的情况,其实反过来想,既然都足够聪明,那么他们都已经意料到这场博弈的结果如何,所以说是当前状态博弈出最后状态,更不如说是最后状态反演出当前状态,已知结果时当前会做怎样的抉择(个人理解).
所以放在这题就是这么思考,首先因为0<a,而a≤x1≤b,x1<y1<x2<y2<..所以我们可以先把非正整数的数过滤掉,只留下正整数,然后再排序,这样就是在一个有序的的正整数序列中选择,那么我们就可以dp[i]就是当前选择了第i个数之后的最大分差,注意是当前,不是先手,也不是后手。那么当前(第i轮)选择完后,(第i+1轮)换下一个人就是下一个人是当前,那第i+1轮的人选择完后,他肯定保证自己是最大分差,所以回到第i轮,能取到的最大分差就是x[i]-max(第i+1的分差),有点绕,详情见代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=;
const int inf=0x3f3f3f3f;
int t,n,m,a,b,x[N],dp[N];//dp[i]为当前操作者取走第i个数的最大分差
int by(int p)
{
if(dp[p]!=-inf)//类似记忆化搜索
return dp[p];
int ans=-inf;
for(int i=p+;i<m&&x[i]-x[p]<=b;i++)
if(x[i]-x[p]>=a)//为什么取最大呢,因为是相等于当前取了p这个数,然后操作轮到下一个人,
ans=max(ans,by(i));//而下一个人足够聪明,那么他的分差应该是最大的
if(ans==-inf)//如果下一个人已经不能操作了,当前最大分差就是当前取的分值
return dp[p]=x[p];
return dp[p]=x[p]-ans;//当前取的分值减去下一操作者能取得的最大分差就是当前最大分差
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&a,&b);
m=;
for(int i=;i<=n;i++)
{
dp[i]=-inf;
scanf("%d",&x[i]);
if(x[i]>)//过滤掉非正整数
x[m++]=x[i];
}
sort(x+,x+m);
x[]=,dp[]=-inf;
printf("%d\n",-by());//因为我多加了个0作为先手,返回的是0-ans,所以答案要取负
}
return ;
}
说好的都聪明,我怎么就不聪明呢
HDU - 4597 Play Game
题目大意:Alice和Bob(这两博弈大佬)在玩一个游戏,有两堆牌,每次Alice和Bob只能从牌堆的两边取走一张牌,并得到相应的分数,问Alice先手最大能取得的分数是多少?
说是博弈dp,其实这题也属于区间dp,我们先用博弈dp解决,和第一题类似我们可以dp[i][j][k][l]表示第一堆还剩i~j,第二堆时还剩k~l时的当前操作者的最大分差,设分差为dis,alice得分a,bob得分b,所有牌取完的总分sum,有x-y=dis,x+y=sum,那么x=(sum+dis)/2,不过思路处理上和上一题有点出入,上一题是挑选了之后去由下一个人的最大分差来得到目前最大分差,这一题是当前有4种挑选结果,然后取最大的分差,详情见代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,inf=0x3f3f3f3f;
int t,n,a[N],b[N],dp[N][N][N][N];//dp[i][j][k][l]第一堆牌剩i~j,第二堆牌剩k~l时当前操作者最大分差
int dfs(int la,int ra,int lb,int rb)
{
if(la>ra&&lb>rb)
return ;
if(dp[la][ra][lb][rb]!=inf)
return dp[la][ra][lb][rb];
int ans=-inf,a1,a2,b1,b2;
if(la<=ra)
{
a1=a[la]-dfs(la+,ra,lb,rb);//挑选a[la]后在下一个人的最大分差下能得到的最大分差
a2=a[ra]-dfs(la,ra-,lb,rb);//挑选a[ra]后在下一个人的最大分差下能得到的最大分差
ans=max(ans,max(a1,a2));
}
if(lb<=rb)
{
b1=b[lb]-dfs(la,ra,lb+,rb);//挑选b[lb]后在下一个人的最大分差下能得到的最大分差
b2=b[rb]-dfs(la,ra,lb,rb-);//挑选b[rb]后在下一个人的最大分差下能得到的最大分差
ans=max(ans,max(b1,b2));
}
return dp[la][ra][lb][rb]=ans;//四种情况取最大即当前最大分差
}
int main()
{
scanf("%d",&t);
while(t--)
{
int sum=;
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
for(int i=;i<=n;i++)
{
scanf("%d",&b[i]);
sum+=b[i];
}
memset(dp,inf,sizeof(dp));
printf("%d\n",(sum+dfs(,n,,n))/);
}
return ;
}
博弈博弈,博一博,变容易
还有区间dp,就是dp[i][j][k][l]表示第一堆还剩i~j,第二堆时还剩k~l时,在剩余分的当前操作者能取到的最大分值。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
int t,n,a[N],b[N],dp[N][N][N][N];//dp[i][j][k][l]第一堆牌剩i~j,第二堆牌剩k~l时当前操作者最大分值
int dfs(int la,int ra,int lb,int rb,int sum)
{
if(la>ra&&lb>rb)
return ;
if(dp[la][ra][lb][rb]!=)
return dp[la][ra][lb][rb];
int ans=;
if(la<=ra)
{
int a1=sum-dfs(la+,ra,lb,rb,sum-a[la]);//剩余的分减去下一个操作者能得到的最大分
int a2=sum-dfs(la,ra-,lb,rb,sum-a[ra]);
ans=max(ans,max(a1,a2));
}
if(lb<=rb)
{
int b1=sum-dfs(la,ra,lb+,rb,sum-b[lb]);
int b2=sum-dfs(la,ra,lb,rb-,sum-b[rb]);
ans=max(ans,max(b1,b2));
}
return dp[la][ra][lb][rb]=ans;
}
int main()
{
scanf("%d",&t);
while(t--)
{
int sum=;
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
for(int i=;i<=n;i++)
{
scanf("%d",&b[i]);
sum+=b[i];
}
memset(dp,,sizeof(dp));
printf("%d\n",dfs(,n,,n,sum));
}
return ;
}
区间区间,区区间间
博弈dp入门 POJ - 1678 HDU - 4597的更多相关文章
- dp入门--poj 1163数塔
...
- 博弈dp 以I Love this Game! POJ - 1678 为例
写在前面的话 知识基础:一些基础的博弈论的方法,动态规划的一些知识 前言:博弈论就是一些关于策略或者游戏之间的最优解,动态规划就是对于一些状态之间转移的一些递推式(or 递归),dp分为很多很多种,比 ...
- 【Mark】博弈类题目小结(HDU,POJ,ZOJ)
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove 首先当然要献上一些非常好的学习资料: 基础博弈的小 ...
- poj 3254 状压dp入门题
1.poj 3254 Corn Fields 状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相 ...
- HDU 2084 数塔(简单DP入门)
数塔 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submiss ...
- POJ 2104&HDU 2665 Kth number(主席树入门+离散化)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 50247 Accepted: 17101 Ca ...
- HDU 5623 KK's Number (博弈DP)
KK's Number 题目链接: http://acm.hust.edu.cn/vjudge/contest/121332#problem/K Description Our lovely KK h ...
- POJ 2342 树形DP入门题
有一个大学的庆典晚会,想邀请一些在大学任职的人来參加,每一个人有自己的搞笑值,可是如今遇到一个问题就是假设两个人之间有直接的上下级关系,那么他们中仅仅能有一个来參加,求请来一部分人之后,搞笑值的最大是 ...
- HDU 2089 不要62【数位DP入门题】
不要62 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
随机推荐
- js 中的 number 为何很怪异
js 中的 number 为何很怪异 声明:需要读者对二进制有一定的了解 对于 JavaScript 开发者来说,或多或少都遇到过 js 在处理数字上的奇怪现象,比如: > 0.1 + 0.2 ...
- go get 安装一个特定版本的包失败解决方法
场景描述 go get 下载第三方包golang gin框架时,会去下载gopkg.in/go-playground/validator.v8包以及gopkg.in/yaml.v2包,gopkg.in ...
- asp.net 5.图片和验证码
1.基本画图 //给用户创建一张图片,并且保持一张图片. //创建一个画布 , )) { //绘画布创建一个画笔 using (Graphics g = Graphics.FromImage(map) ...
- JS基础_质数练习,用到了标记flag
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 题解 P2879 【[USACO07JAN]区间统计Tallest Cow】
题目链接: https://www.luogu.org/problemnew/show/P2879 思路: 先不管最大高度,我们读入一对x,y.说明,x+1~y-1之间牛的身高都小于x,y. 然后不妨 ...
- Fox新闻报道,帮助北朝鲜使用加密货币专家被捕
根据司法部的刑事诉讼,一名美国加密货币专家周四在洛杉矶被捕,原因是涉嫌帮助朝鲜使用加密货币逃避美国的制裁.网民都说敢帮助敌人,就应该关起来.
- Guava动态调用方法
前言 大家在Coding的时候,经常会遇到这样一个情况,根据不同的条件去执行对应的代码.我们通常的处理方式是利用if-else判断,或者直接switch-case,特别是jdk1.6之后,swith开 ...
- 【1】Zookeeper概述
一.前言 在"网络是不可靠的"这一前提下,分布式系统开发需要解决如下四个问题: 客户端如何访问众多服务? 解决方案:服务聚合,使用API网关 服务于服务之间如何通信? 解决方案 ...
- ansible 配置文件设置
目录 ansible 配置文件设置 一.ansible configuration settings 二.ansible 配置文件查找顺序(从上到下,依次查找) 三.附录ansible配置参数 ans ...
- jsonp的原理介绍及Promise封装
什么叫jsonp? jsonp是json with padding(填充式json或参数式json)的简写,是通过ajax请求跨域接口,获取数据的新实现方式 jsonp的实现原理: 动态创建scrip ...