zoukankan      html  css  js  c++  java
  • 蓝桥杯 试题 历届试题 填字母游戏 博弈+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的,即是必输的状态。

  • 相关阅读:
    开发小技巧: 如何在jQuery中禁用或者启用滚动事件.scroll java程序员
    Spell Checker 新版Chrome的纠错特性 java程序员
    45个漂亮且有创意的HTML5网站展示 java程序员
    70个jquery触摸事件插件——支持手势触摸! java程序员
    40个超酷的jQuery动画教程 java程序员
    极客技术专题【002期】:开发小技巧 如何使用jQuery来处理图片坏链? java程序员
    30个热门的CSS3 Image Hover 脚本 java程序员
    2013年三月GBin1月刊 java程序员
    插入1000万数据的几种优质算法
    批量上传图片(带百分比进度显示)项目源码
  • 原文地址:https://www.cnblogs.com/w-like-code/p/12920250.html
Copyright © 2011-2022 走看看