本来博弈还没怎么搞懂,又和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. 并不对劲的CF1237D&E:Balanced Playlist and Binary Search Trees

    CF1237D Balanced Playlist 题意 有一个长度为\(n\)(\(n\leq 10^5\))的循环播放歌单,每首歌有一个优秀值\(a_i\)(\(a_i\leq 10^9\)). ...

  2. luogu P2423 [HEOI2012]朋友圈 (最大团)

    在很久很久以前,曾经有两个国家和睦相处,无忧无虑的生活着. 一年一度的评比大会开始了,作为和平的两国,一个朋友圈数量最多的永远都是最值得他人的尊敬,所以现在就是需要你求朋友圈的最大数目.两个国家看成是 ...

  3. C# 反射遍历对象所有属性

    [TestMethod] public void Test6() { List<RepaymentRecord> repaymentList = new List<Repayment ...

  4. 【weixi】微信支付---微信公众号JSAPI支付

    一.JSAPI支付 JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付.应用场景有: ◆ 用户在微信公众账号内进入商家公众号,打 ...

  5. 深入理解hive之事务处理

    事务的四个特性 1.automicity:原子性 2.consistency:一致性 3. isolation:独立性 4.durability:持久性 5.支持事务有几个条件需要满足:1.所有的事务 ...

  6. MongoDB 基础增删改查

    增删改查 基础操作 use show dbs show collections db[当前所在数据库] 插入文档 db.collection.insert() db.collection.insert ...

  7. vue-过滤器-时间戳转换

    main.js // 将时间戳转日期格式的过滤器 Vue.filter('dateFormat', (dataStr) => { var time = new Date(dataStr); fu ...

  8. vue中的常用三元

    点击事件的三元 <el-button type="primary" @click="edit == 'mod' ? sureModify() : submit()& ...

  9. centos7andcentos6初始化脚本

    #!/bin/bash # get OS verison RELEASEVER=$(rpm -q --qf "%{Version}" $(rpm -q --whatprovides ...

  10. Linux监控服务并主动重启

    Linux查询后台进程,如果没有进程号,则重启服务: #!/bin/sh basepath=$(cd ``; pwd) while true do procnum=`ps -ef|grep " ...