zoukankan      html  css  js  c++  java
  • 第十三次CCF第四题 1803——04 博弈

    我又写了一个简洁版的2.0; 可以作为博弈搜索树的模板  ; 

    https://www.cnblogs.com/xidian-mao/p/9389974.html

        废话ps: 开始觉得这是一道简单得博弈 3*3暴力肯定可以解决问题   刚该开始得思路是直接dfs()判断谁输谁赢了,后来发现题意要输出最优解得情况(最后卡在哪好久:

    还是自己太自信了: 最后五点去上了个厕所;路上想到了dfs可以返回赢的最小步数和输的最大步数这应该是最优解了-----T&T 最后没时间交了,回来补得,试了一些数据感觉没有问题,如果有bug欢迎指出,还是自己太菜了)

    题目分析:

    博弈——每个人采取最优策略,问最后有几个空格;

    首先写一个check()判断现在得局面 谁赢谁输 平局 还是继续可以下  这个暴力枚举即可

     1 int check () {
     2     for (int i=1;i<=3;i++) {
     4         int x=mp[i][1];  
     5         if (x==0) continue;
     6         for (int j=1;j<=3;j++) {
     7             if (mp[i][j]!=x)
     8                 break;
     9             if (j==3)
    10                 return x;
    11         }
    12     }
    13      for (int i=1;i<=3;i++) {
    14         int x=mp[1][i];
    15         if (x==0) continue;
    16         for (int j=1;j<=3;j++) {
    17             if (mp[j][i]!=x)
    18                 break;
    19             if (j==3)
    20                 return x;
    21         }
    22     }
    23     int x=mp[1][1];
    24     if (x&&mp[1][1]==mp[2][2]&&mp[2][2]==mp[3][3]) return x;
    25     x=mp[2][2];
    26     if (x&&mp[3][1]==mp[2][2]&&mp[2][2]==mp[1][3])  return x;
        if (num==0)  return 0;
    27 return -1; 28 }

    check()返回值:

    0:平局

    1:1赢

    2: 2赢

    -1:局面可以继续下

    核心int  dfs(x,y,p) // 作用: 当p选手在x,y位置放下棋子时如果必赢,最少赢多少步,如果必输,最多可以输多少步;

    思路转变当你放下一个棋子还不能赢得比赛胜利时,比赛得主动权已经移交给对方了

    此时对方dfs()遍历搜索最优路径,只有当对方必败时,你才会赢, 只要对方有一种情况可以赢,你就要gg了

    对方如果一定会赢 会选择最小赢得步数  这个路径也是你输得步数+1

    如果对方一定会输 她会选择一个输得最大步数  这个步数等于你赢得步数+1;

    关键点:你下完之后主动权已经在于对方 对方得最优策略才是你下完这一步得最终结果

    dfs():返回值

    x>0 :必赢下最下步数是x

    x==0 :是平局

    x<0 :必输下最多得步数

     1 int dfs (int x,int y,int t)  {
     2     mp[x][y]=t; num--;
     3     int ans=check();
     4     if (ans==t)  { mp[x][y]=0; num++; return 1; }  // 下完这一步立即获胜
     5     if (ans==0)  { mp[x][y]=0; num++; return 0; }  // 下完这一步平局  // 不存在你下完就立即输。。。。。
     6     int k=1;
     7     if (t==1)  k=2;// k 交换主动权 你下完之后得最终结果取决于对方
     8     int m1=100;//  初始化赢得最小步
     9     int m2=0;// 输得最大步 (用负数表示)
    10     ans=-1;// 假设对方一定输
    11     for (int i=1;i<=3;i++)       {
    12         for (int j=1;j<=3;j++) {
    13             if (mp[i][j]==0) {
    14                 int tmp=dfs (i,j,k);
    15                 ans=max (ans,tmp);// 只要对方一种情况赢, ans就大于0, t一定会输
    16                 if (tmp>0)  {
    17                    m1=min(m1,tmp);// 赢得最小步
    18                 }
    19                 if (tmp<0) {
    20                     m2=min(m2,tmp);//输得最大步 (用负数表示)
    21                 }
    22             }
    23         }
    24     }
    25     mp[x][y]=0;   num++;
    26     if (ans==0)   return 0;
    27     if (ans>0)   return -(m1+1);// 如果对方会赢 你就输这个步数取决于对方
    28     return -(m2-1);//对方无论怎么走都输

    完整代码   (本人qq 821474143  如果想的不周全,欢迎大家指教_

    
    

    #include <bits/stdc++.h>
    using namespace std;
    int mp[10][10];
    int num1,num2;// num1 1数目  num2 2数目
    int num;// 空格数目
    int n;
    int check () {
        for (int i=1;i<=3;i++) {
            int x=mp[i][1];
            if (x==0) continue;
            for (int j=1;j<=3;j++) {
                if (mp[i][j]!=x)
                    break;
                if (j==3)
                    return x;
            }
        }
         for (int i=1;i<=3;i++) {
            int x=mp[1][i];
            if (x==0) continue;
            for (int j=1;j<=3;j++) {
                if (mp[j][i]!=x)
                    break;
                if (j==3)
                    return x;
            }
        }
        int x=mp[1][1];
        if (x&&mp[1][1]==mp[2][2]&&mp[2][2]==mp[3][3]) return x;
        x=mp[2][2];
        if (x&&mp[3][1]==mp[2][2]&&mp[2][2]==mp[1][3])  return x;
        if (num==0)  return 0;
        return -1;
    }
    int dfs (int x,int y,int t)  {
        mp[x][y]=t;  num--;
        int ans=check();
        if (ans==t)  { mp[x][y]=0; num++; return 1; }
        if (ans==0)  { mp[x][y]=0; num++; return 0; }
        int k=1;
        if (t==1)  k=2;
        int m1=100;
        int m2=0;
        ans=-1;
        for (int i=1;i<=3;i++)       {
            for (int j=1;j<=3;j++) {
                if (mp[i][j]==0) {
                    int tmp=dfs (i,j,k);
                    ans=max (ans,tmp);
                    if (tmp>0)  {
                       m1=min(m1,tmp);
                    }
                    if (tmp<0) {
                        m2=min(m2,tmp);
                    }
                }
            }
        }
        mp[x][y]=0;  num++;
        if (ans==0)   return 0;
        if (ans>0)   return -(m1+1);
        return -(m2-1);

    
    

    }
    int main ()
    {
        cin>>n;
        while (n--) {
            num1=0;
            num2=0;
            for (int i=1;i<=3;i++)
                for (int j=1;j<=3;j++) {
                    cin>>mp[i][j];
                    if (mp[i][j]==1) num1++;
                    else if (mp[i][j]==2) num2++;
                }
            num=3*3-num1-num2;
            int ans=check();
            //cout<<ans<<endl;
            if (ans==1)  cout<<num+1<<endl;
            else if (ans==2) cout<<-(num+1)<<endl;
            else if (ans==0) cout<<"0"<<endl;
            else {
                int m1=100;
                int m2=0;
                int x=2;
                if (num1==num2)  x=1;
                int ans=-1;
                for (int i=1;i<=3;i++)       {
                    for (int j=1;j<=3;j++) {
                        if (mp[i][j]==0) {
                             int t=dfs (i,j,x);
                              ans=max (ans,t);
                              if (t>0) {
                                m1=min (t,m1);// 赢得最小步数
                              }
                              if (t<0) {
                                m2=min (t,m2);  //输的最大步数
                              }
                        }
                     }
                }
                if (ans>0)       
                  if (x==1) cout<<num-m1+1<<endl;
                  else      cout<<-(num-m1+1)<<endl;
                else if (ans==0)   cout<<"0"<<endl;
                else   
                  if (x==2)  cout<<num+m2+1<<endl;
                  else       cout<<-(num+m2+1)<<endl;
            }
        }
        return 0;
    }

    
    

     一个典型得数据

    1 0 0

    0 0 0

    0 0 2

    电脑给出的是1赢 你能一次走对使1赢吗?真是有趣

    博弈___ xdoj+1045

    定义一种新的黑白棋:

    1. 棋盘大小为5*5的格子;

    2. 有些格子不能放棋子;

    3. 同一个格子最多放一个棋子;

    4. 先手执白棋,后手执黑棋;

    5. 先手第一次可以把棋放在任意可以放的位置上;

    6. 接下来两人轮流放棋子,这个棋子必须与上一个人放的棋子相邻

    请问:两人都是最优策略,是先手赢,还是先手输?

    输入

    有多组输入数据,第一行为一个数字T,代表有T组输入数据 (0<T≤10)。

    接下来为T组数据。

    每组数据分5行、每行5个数字构成,每个数字为0或1。0表示这个位置可以放棋子,1表示这个位置不能放棋子。

    输出

    对于每组数据,在一行上输出“win”或“lose”,表示先手赢或输。

    样例输入

    2	
    11111
    11111
    11111
    11111
    00000
    11111
    11111
    11111
    11111
    10000
    

    样例输出

    win
    lose

    暴力枚举!!!
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int n=5;
     4 bool  mp[10][10];// 地图 每一格能否放
     5 bool visit[10][10];// 遍历访问
     6 int dx[]={0,0,-1,1};
     7 int dy[]={1,-1,0,0};
     8 bool dfs (int x, int y) {
     9     visit[x][y]=1;
    10     int flag=1;
    11     for (int i=0;i<4;i++) {
    12         int tx=x+dx[i];
    13         int ty=y+dy[i];
    14         if (tx>=1&&tx<=n&&ty>=1&&ty<=n&&!visit[tx][ty]&&!mp[tx][ty]) {
    15             int tmp=dfs (tx,ty);
    16             if (tmp)  {
    17                 flag=0;
    18                 break;
    19             }
    20         }
    21     }
    22     visit[x][y]=0;
    23     return flag;
    24 }
    25 int main ()
    26 {
    27     int T;
    28     scanf ("%d",&T);
    29     while (T--) {
    30         for (int i=1;i<=n;i++)
    31             for (int j=1;j<=n;j++) 
    32                 scanf ("%1d",&mp[i][j]);
    33         int flag=0;
    34         for (int i=1;i<=n&&!flag;i++)// 二重循环的遍历的问题
    35             for (int j=1;j<=n;j++) {
    36                 memset (visit,0,sizeof(visit));
    37                 if (!mp[i][j]) {
    38                     flag=dfs (i,j);
    39                     if (flag) break;
    40                 }
    41             }
    42         if (flag)  printf ("win
    ");
    43         else       printf ("lose
    ");
    44     }
    45     return 0;
    46 }
     
    抓住青春的尾巴。。。
  • 相关阅读:
    webpack --- 详解
    vue 配置文件详解
    webstorm添加vue模板支持
    golang制作系统服务
    PMBOK 项目管理 九大知识领域和五大流程
    人工智能——数据、信息与知识
    阿里云大数据三次技术突围:Greenplum、Hadoop和“飞天”
    海量数据处理利器greenplum——初识
    CentOS如何禁用root本地或远程ssh登录
    Tomcat学习—Tomcat的简介和目录以及配置文件介绍(Windows环境)
  • 原文地址:https://www.cnblogs.com/xidian-mao/p/8601683.html
Copyright © 2011-2022 走看看