本来博弈还没怎么搞懂,又和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. C#发送Outlook邮件(仅SMTP版本)

    先表明Outlook的参数:网址:https://support.office.com/zh-cn/article/Outlook-com-%E7%9A%84-POP%E3%80%81IMAP-%E5 ...

  2. bat 将war文件转换成ear文件

    1.无需拷贝war文件,自动获取war set path=%path%;D:\jdk\jdk1.6.0_31\bin;C:\Program Files\7-Zip del **0001-control ...

  3. 浅读vue-router源码,了解vue-router基本原理

    项目中使用vue-router的时候,会进行以下操作(可能具体不是这么写的,但是原理一样): 定义映射关系routes: 定义router实例的时候传入vue和参数{routes...}: 定义vue ...

  4. 服务端相关知识学习(一)之什么是zookeeper

    什么是zookeeper zookeeper是分布式协调服务,可以在分布式系统中共享配置.协调锁资源.提供命名服务那分布式协调服务又是个什么东西呢?首先我们来看“协调”是什么意思.在一个并发的环境里, ...

  5. O058、Snapshot Volume 操作

    参考https://www.cnblogs.com/CloudMan6/p/5657744.html   Snapshot 可以为 volume 创建快照,快照中保存了 volume当前的状态,以后可 ...

  6. R语言学习笔记:读取前n行数据

    常规读取 一般我们读取文件时都会读取全部的文件然后再进行操作,因为R是基于内存进行计算的. data <- read.table("C:\\Users\\Hider\\Desktop\ ...

  7. hadoop-2.7.3安装kafka_2.11-2.1.0

    软件下载: http://mirrors.shu.edu.cn/apache/kafka/2.1.0/kafka_2.11-2.1.0.tgz 把下载好的包kafka_2.11-2.1.0.tgz 上 ...

  8. vue中移动端滚动事件,点击一次触发了事件两次(better-scroll)

    解决办法一: 将button标签换成a标签 问题代码: <span class="submitBtn" @click.stop="replyReport()&quo ...

  9. bisect:维护一个有序的列表

    介绍 bisect模块实现了一个算法来向列表中插入元素,同时仍然保证列表有序 有序插入 import bisect ''' 可以使用bisect.insort向一个列表中插入元素 ''' values ...

  10. linux之网络命令

    本文整理了在实践过程中使用的Linux网络工具,这些工具提供的功能非常强大,我们平时使用的只是冰山一角,比如lsof.ip.tcpdump.iptables等. 本文不会深入研究这些命令的强大用法,因 ...