• 蓝桥杯 试题 历届试题 填字母游戏 博弈+dfs剪枝


    问题描述
      小明经常玩 LOL 游戏上瘾,一次他想挑战K大师,不料K大师说:
      “我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了”。


      K大师在纸上画了一行n个格子,要小明和他交替往其中填入字母。


      并且:


      1. 轮到某人填的时候,只能在某个空格中填入L或O
      2. 谁先让字母组成了“LOL”的字样,谁获胜。
      3. 如果所有格子都填满了,仍无法组成LOL,则平局。


      小明试验了几次都输了,他很惭愧,希望你能用计算机帮他解开这个谜。
    输入格式
      第一行,数字n(n<10),表示下面有n个初始局面。
      接下来,n行,每行一个串,表示开始的局面。
      比如:“******”, 表示有6个空格。“L****”, 表示左边是一个字母L,它的右边是4个空格。
    输出格式
      要求输出n个数字,表示对每个局面,如果小明先填,当K大师总是用最强着法的时候,小明的最好结果。
      1 表示能赢
      -1 表示必输
      0 表示可以逼平
    样例输入
    4
    ***
    L**L
    L**L***L
    L*****L
    样例输出
    0
    -1
    1
    1

    //解题思路:这一题是含有平局的无偏博弈问题。博弈问题一般思路:
    f( 当前局势  )
    {
        临界条件
        
        t = 负
        for( 所有步数 ){
            t = f(尝试走一步)
            if( t==负 ) return 胜
            if( t==平 ) t = 平
        }
        return t
    }
    即尝试一步,改变当前局势,交给对方处理。每一方都尽可能希望胜利,其次平局。
    这里直接用dfs()会超时,可以用C++ map 将一个局势 和 最终结果一一对应。 map.find()如果未找到 则 == map.end()  string.find()未找到返回-1
     
    //实现代码:
    #include<iostream>
    #include<string>
    #include<map>
    using namespace std;
    
    //输入 
    int n;
    string str;//当前状态 
    
    map<string,int> m;//键值对 用来把相同状况剪枝
    
    int dfs(string str)// 返回  1 0 -1
    {
        if( m.find(str)!=m.end() ){
            return m[str];//如果重复 剪枝 
        }
        
        if( (str.find("LO*")+1)||(str.find("*OL")+1)||(str.find("L*L")+1)){
            return m[str] = 1;//如果发现任意一个 则胜利(+1后返回值>=1 未找到返回0) 
        }
    /***    上面代码如果改为 
        if( str.find("LOL") ){
            return m[str] = -1;//如果发现任意一个 则胜利(+1后返回值>=1 未找到返回0) 
        } 
            逻辑上也是对的 但运行会超时 大概是多了不必要的递归  ***/
        if( str.find('*')==-1 ){
            return m[str] = 0;//没有空位* 则平局 
        }
        
        int flat = -1;
        for(int i=0; i<str.length(); i++)
        {
            if( str[i] != '*' )
            {
                continue;
            }
            //尝试两种方式 
            str[i] = 'L';
            if( dfs(str)==-1 ){
                str[i] = '*';//这里要先回溯为传入时的状态 再存入map 
                return m[str] = 1;
            }
            
            if( dfs(str)==0 ){
                flat = 0;
            }
            
            str[i] = 'O';
            if( dfs(str)==-1 ){
                str[i] = '*';
                return m[str] = 1;
            }
            
            if( dfs(str)==0 ){
                flat = 0;
            }
            
            str[i] = '*';//回溯 
        }
        
        return m[str] = flat;
    }
    
    void solve()
    {
        int res = dfs(str);
        cout<<res<<endl;
    }
    
    int main()
    {
        cin>>n;
        while( n-- )
        {
            cin>>str;
            solve();
        }
        return 0;
    }

     先回溯再存如map:回溯前的状态是返回-1的,即是必输的状态。

  • 相关阅读:
    try catch in php
    druid德鲁伊数据库密码加密
    mysql 1093
    MySQL Delete语句不能用别名
    SQL筛选两个字段同时满足多个条件的结果
    MySQL 查询有效小数位数大于两位的值
    我们慌慌张张,不过图碎银几两
    查看Linux服务器端口占用情况,网络情况和CPU使用情况
    Gitbash命令行管理项目
    IDEA中Git的用户名修改
  • 原文地址:https://www.cnblogs.com/w-like-code/p/12920250.html
Copyright © 2020-2023  润新知