本来博弈还没怎么搞懂,又和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的更多相关文章

  1. dp入门--poj 1163数塔

                                                                                                        ...

  2. 博弈dp 以I Love this Game! POJ - 1678 为例

    写在前面的话 知识基础:一些基础的博弈论的方法,动态规划的一些知识 前言:博弈论就是一些关于策略或者游戏之间的最优解,动态规划就是对于一些状态之间转移的一些递推式(or 递归),dp分为很多很多种,比 ...

  3. 【Mark】博弈类题目小结(HDU,POJ,ZOJ)

    转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 首先当然要献上一些非常好的学习资料: 基础博弈的小 ...

  4. poj 3254 状压dp入门题

    1.poj 3254  Corn Fields    状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相 ...

  5. HDU 2084 数塔(简单DP入门)

    数塔 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submiss ...

  6. POJ 2104&HDU 2665 Kth number(主席树入门+离散化)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 50247   Accepted: 17101 Ca ...

  7. HDU 5623 KK's Number (博弈DP)

    KK's Number 题目链接: http://acm.hust.edu.cn/vjudge/contest/121332#problem/K Description Our lovely KK h ...

  8. POJ 2342 树形DP入门题

    有一个大学的庆典晚会,想邀请一些在大学任职的人来參加,每一个人有自己的搞笑值,可是如今遇到一个问题就是假设两个人之间有直接的上下级关系,那么他们中仅仅能有一个来參加,求请来一部分人之后,搞笑值的最大是 ...

  9. HDU 2089 不要62【数位DP入门题】

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

随机推荐

  1. 使用JavaScript和React编写原生移动应用

    使用JavaScript和React编写原生移动应用 React Native使你只使用JavaScript也能编写原生移动应用. 它在设计原理上和React一致,通过声明式的组件机制来搭建丰富多彩的 ...

  2. NYOJ 石子合并(一) 区间dp入门级别

    描述    有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价 ...

  3. 10.Bash的安装

    10.Bash的安装本节提供了在 Bash支持的不同系统上的基本安装指导.本版本支持 GNU操作系统,几乎每个 UNIX版本,以及几个非 UNIX 系统,例如 BeOS 和 Interix.还有针对 ...

  4. WAV格式文件无损合并&帧头数据体解析(python)(原创)

    一,百度百科 WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频 ...

  5. gRPC 和 C#

    前些天gRPC 发布1.0 版本,代表着gRPC 已经正式进入稳定阶段. 今天我们就来学习gRPC C# .而且目前也已经支持.NET Core 可以实现完美跨平台. 传统的.NET 可以通过Mono ...

  6. asp.net 13 缓存,Session存储

    1.缓存 将数据从数据库/文件取出来放在服务器的内存中,这样后面的用来获取数据,不用查询数据库,直接从内存(缓冲)中获取数据,提高了访问的速度,节省了时间,也减轻了数据库的压力. 缓冲空间换时间的技术 ...

  7. git的详细安装

    git的详细安装 Git 是时候动手尝试下 Git 了,不过得先安装好它.有许多种安装方式,主要分为两种,一种是通过编译源代码来安装:另一种是使用为特定平台预编译好的安装包. 从源代码安装 若是条件允 ...

  8. arcgisJs之featureLayer中feature的获取

    arcgisJs之featureLayer中feature的获取 在featureLayer中source可以获取到一个Graphic数组,但是这个数组属于原数据数组.当使用 applyEdits修改 ...

  9. Centos7:Redis的安装,配置及使用

    安装依赖与环境 yum install gcc-c++ 解压缩redis 编译,进入redis源码目录 make 安装 make install PREFIX=/usr/local/redis 注:P ...

  10. 1 sql server中添加链接服务器

    1  链接到另一个sql server 的实例 exec sp_addlinkedserver @server= '服务器的地址',@srvproduct='SQL Server' go 分布式查询中 ...