[CSP校内集训]贪吃蛇(阿尔法-贝塔剪枝)

题目

有两条蛇(1号蛇和2号蛇)在n行m列的地图上,地图上有障碍物。一条蛇碰到蛇身/障碍物/边界就会死。蛇身会不断长长——可以理解为蛇尾位置不会变,蛇只会向前伸展不会缩尾巴。两条蛇都绝顶聪明,如果自己能赢,一定会尽量快地赢;如果自己会输,一定会死得尽量晚。给出初始局面,两蛇轮流走,每次可以且必须向上下左右移动一格。1号蛇先走,请告诉我谁会在多少回合时赢。\((n,m\leq 20)\)且\(0\)的数量不超过\(50\)


\(\alpha - \beta\)剪枝

AlphaBeta剪枝算法是一个搜索算法,旨在减少在其搜索树中,被极大极小算法评估的节点数。
这是一个常用人机游戏对抗的搜索算法。它的基本思想是根据上一层已经得到的当前最优结果,决定目前的搜索是否要继续下去——百度百科

前提:双方绝顶聪明,各自为营

用我的话来说,这个剪枝方法是这样的一个结构:

  1. 所有的估价都是由同一个角度来看待的,不能说在1的回合说对1有利,在2的回合又说对2有利(应该说对1有害)
  2. 搜索树上先手通过一条边转移成后手
  3. 搜索树的叶子节点是估价函数,评估到达的这个状态的好坏,函数值越大对先手越有利,父亲节点的权值均由儿子转移来
  4. 奇偶性不同的层求的东西不一样,即两个人的策略不同,先手求的是所有儿子中最大的一个(即对先手最有利),后手求的是最小的一个(对先手最有害)

总而言之,就是搜索树的奇数层节点取\(max\),偶数层取\(min\),叶子节点需要自己估价(根据具体的题目)

扯了半天,如何剪枝?很简单,比如对于先手节点\(u\),它会取最大的儿子,假设当前权值为\(ans_u\),如果当前节点的儿子\(v\)的一个儿子\(vv\)权值小于\(ans_u\),就不用再遍历这个儿子\(v\)剩下的儿子了(因为儿子\(v\)的权值取\(min\){孙子}),这个儿子\(v\)的权值到目前为止可以判断一定小于\(ans_u\)了;后手相反(可能会有点抽象,建议画图理解)


本题思路

本题显然可以用\(\alpha - \beta\)剪枝(双方绝顶聪明且操纵的蛇不一样)

主要是估价函数的设计:如果先手无路可走,就是绝对有害,设为\(-inf\),但又活的越久越好,所以还要加上一个存活时间\(step\),后手同理

这个剪枝还是比较简单好理解的,主要注意不要把先后大小关系搞反了就行

Code(即本题的标程

#include<bits/stdc++.h>
#define N 25
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
const int INF = 10000;
int n,m,a[N][N],sx[2],sy[2];
int dox[4]={0,1,0,-1},doy[4]={1,0,-1,0};

template <class T>
void read(T &x)
{
    char c;int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}
int dfs(int step,int player,int alpha,int beta,int fx,int fy,int px,int py)//alpha是下界只降不增,beta是上界只增不降
{
    bool flag=false;
    int ans=(player==1 ? beta : alpha);//如果是1就会选尽量大
    for(int i=0;i<4;++i)
    {
        int dx=fx+dox[i],dy=fy+doy[i];
        if(dx<1||dy<1||dx>n||dy>m||a[dx][dy]) continue;
        flag=true;
        a[dx][dy]=1;
        int now=0;
        if(player==1) now=dfs(step+1,2,alpha,ans,px,py,dx,dy);//1号
        else now=dfs(step+1,1,ans,beta,px,py,dx,dy);
        a[dx][dy]=0;
        if(player==1)//注意这里的玩家1在上面的剪枝中相当于后手的儿子
        {
            if(now>=alpha) return alpha;
            //如果now比最小值大,那么这个节点会贡献值一定大于等于now,而最小值一定不会考虑它
            else ans=Max(ans,now);
        }
        else//它的父亲是先手,和上面讨论的一致
        {
            if(now<=beta) return beta;
            else ans=Min(ans,now);
        }
    }
    if(!flag)//移动不了,即到了叶子(输),需要估价
    {
        if(player==1) return -INF+step;//step越大先手活的越久,但总体上还是自己输了
        else return INF-step;//step越大对于先手越坏,但总体上还是对面赢了
    }
    return ans;
}
int main()
{
    freopen("h.in","r",stdin);
    freopen("h.out","w",stdout);
    read(n);read(m);
    for(int i=1;i<=n;++i)
      for(int j=1;j<=m;++j)
      {
        read(a[i][j]);
        if(a[i][j]==1) sx[0]=i,sy[0]=j;
        if(a[i][j]==2) sx[1]=i,sy[1]=j;
      }

    int ans=dfs(1,1,INF,-INF,sx[0],sy[0],sx[1],sy[1]);
    if(ans>0) printf("1 %d\n",INF-ans);//最后到达的是2号对应的叶子,减掉INF还原
    else printf("2 %d\n",ans+INF);//最后到达的是1号对应的叶子,加上INF(这个见上面dfs中估价函数的计算)
    return 0;
}

\(learning from\):博客1博客2

P.S. 笔者小白一枚,如有错误还请指出

原文地址:https://www.cnblogs.com/Chtholly/p/11650808.html

时间: 2024-09-30 10:41:11

[CSP校内集训]贪吃蛇(阿尔法-贝塔剪枝)的相关文章

2017秋-软件工程第七次作业(1)-【探路者】贪吃蛇阿尔法发布展示(视频展示)

Part One [探路者]选题展示视频链接: http://www.iqiyi.com/w_19ruzx6xud.html Part Two [贪吃蛇]阿尔法发布视频截图 1视频的前半部分是介绍功能区域. 2后半部分是介绍小蛇吃单词的功能. Part Three[贪吃蛇]制作过程(核心难点突破) 1使用绘声绘影软件制作. 2消除声音中的噪音. Part Five [贪吃蛇]制作细节(素材+准备+创意构思) 1米赫同学负责构思视频制作流程.使用录屏软件进行录制.撰写脚本对录制的软件进行介绍.同时

[CSP校内集训]attack(DAG支配树)

题意 给一个DAG,多次询问,每次给定\(k\)个点,求1到这些点的必经点的交集大小 思路 支配树裸题,建好DAG的支配树后\(k\)个点LCA的深度即为答案 Code #include<bits/stdc++.h> #define N 100005 using namespace std; int n,m,q; int rd[N],f[N][18],dep[N]; struct Edge { int next,to; }edge[N<<1],edge1[N<<1];i

[CSP校内集训]tree(期望DP)

题意 给一颗树,从1节点出发,走每条边的概率相同且耗时为1,求每个点第一次被遍历到的期望时间(\(t_1=1\)) 思路 在树上只有两种移动方式:从儿子到父亲,从父亲到儿子 假设从\(rt\)走到\(v\)的期望代价为\(dow_i\),从\(i\)走到\(rt\)的期望代价为\(val_i\) 假设从\(rt\)转移到\(v\),\(rt\)的度数为\(k\),\(rt\)的父亲为\(fa\),则: \[dow_v = \frac{1}{k} + \sum_{son}^{son\neq v}

[CSP校内集训]rank

题意 给出一个字符串后缀排序之后的数组\(sa_i\),求原字符串(字典序最小),无解输出-1 思路 显然从\(rk_1\)开始填字符是可以保证字符单调不降的 找到\(sa\)值相邻的两个位置,现在需要知道\(rk_i\)和\(rk_{i+1}\)是否可以填相邻字符:当它们填相同字符时需要比较后一位,如果相对关系相同则可行(因为后一位默认已经成立) 举个栗子:\(4,2,3,1\),查看4能不能和3填同一个字符,则判断后一位2和1:而\(4>3 \&\& 2>1\),所以可以相

[CSP校内集训]矩形面积交(树状数组)

题意 给\(n\)个互不相交的矩形,再给\(m\)个询问,每次给一个矩形求它与这\(n\)个矩形的面积交 思路 自己写的太丑了导致DEBUG了一个半小时qwq 一对矩形的交可以拆分成二维前缀和形式下的矩形的交,于是变成判断16次矩形的交(不想画图...只想口胡) 这些矩形都有\(x_0=0,y_0=0\),即左下角为坐标原点,于是一个矩形可以只用右上角的坐标表示: 对于一个询问的矩形\((x,y)\)和另一个矩形\((x_i,y_i)\),它们的交为\(min(x,x_i)\times min(

[CSP校内集训]pestc(拓扑排序)

题意 给一个边带权的有向图,可以花费边权使得一条边反向:通过翻转边让原图变成一个DAG,要求是所有花费中的最大值最小\(,(n,m\leq 200000)\),保证无重边和自环 解法1 考场上没看出来性质,于是口胡了一个乱搞做法 连好边后直接对原图进行一遍拓扑排序,由于原图不是DAG,所以会有无法入队的环存在:如果当前队列为空而有点没有被遍历到,那么就强行选择一个点将连向它的边翻转: 具体的,我们选择\((max(\) 连向\(i\)的边 \())\)最小的\(i\),由于翻转了连向\(i\)的

小项目特供 贪吃蛇游戏(基于C语言)

C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次. 是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第二天写了第二版和第三版. 相信C语言写个小游戏或小项目是大多数计算机相关专业的学生都做的事情,但是作为一个数学专业的学生,我们教研室的老师对C语言的要求也就比较低了,大一没有让我们做个小项目实践一次.至今为止用C/C++做过的三个小项目(大作业),一个是外校同学让我帮忙写的学生信息管理系统(天呐,这

【探路者】贪吃蛇β发布展示(视频展示)

Part One [探路者]选题展示视频链接: http://www.iqiyi.com/w_19rv0segft.html Part Two [贪吃蛇]阿尔法发布视频截图 1首先展示了新添加的欢迎界面.并加入了词库选择功能 2.展示了对界面的美化. 3. 展示了新加入的音乐功能 4.后半部分是整体玩法的展示,并修改了α发布的bug Part Three[贪吃蛇]制作过程(核心难点突破) 1使用绘声绘影软件制作. 2消除声音中的噪音. Part Five [贪吃蛇]制作细节(素材+准备+创意构思

安卓贪吃蛇项目包!!

我在博客上看见很多有关于安卓开发贪吃蛇的博文,但是都不知道他们所用的软件.版本是什么,所以在自己下载的软件上运行的时候总是出不来结果,作为一只安卓课程老师只上了一节课就让我们自己做课程设计的菜鸟来说,这是何其困哪的一件事,安卓什么也不懂,运行环境也是一点也不熟悉.我们老师要求我们用eclipse来运行,有没有人是用这个做过的啊?求帮助!!真的是不会了,找了很多的项目包运行的时候都会出错,永远不会出现贪吃蛇的界面,宝宝真的快疯了.还附上了我所用的软件,有没有好心人解答下这个问题. 本来打算私聊项目