蓝桥杯 试题 历届试题 填字母游戏 博弈+dfs剪枝
问题描述
小明经常玩 LOL 游戏上瘾,一次他想挑战K大师,不料K大师说:
“我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了”。
K大师在纸上画了一行n个格子,要小明和他交替往其中填入字母。
并且:
1. 轮到某人填的时候,只能在某个空格中填入L或O
2. 谁先让字母组成了“LOL”的字样,谁获胜。
3. 如果所有格子都填满了,仍无法组成LOL,则平局。
小明试验了几次都输了,他很惭愧,希望你能用计算机帮他解开这个谜。
“我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了”。
K大师在纸上画了一行n个格子,要小明和他交替往其中填入字母。
并且:
1. 轮到某人填的时候,只能在某个空格中填入L或O
2. 谁先让字母组成了“LOL”的字样,谁获胜。
3. 如果所有格子都填满了,仍无法组成LOL,则平局。
小明试验了几次都输了,他很惭愧,希望你能用计算机帮他解开这个谜。
输入格式
第一行,数字n(n<10),表示下面有n个初始局面。
接下来,n行,每行一个串,表示开始的局面。
比如:“******”, 表示有6个空格。“L****”, 表示左边是一个字母L,它的右边是4个空格。
接下来,n行,每行一个串,表示开始的局面。
比如:“******”, 表示有6个空格。“L****”, 表示左边是一个字母L,它的右边是4个空格。
输出格式
要求输出n个数字,表示对每个局面,如果小明先填,当K大师总是用最强着法的时候,小明的最好结果。
1 表示能赢
-1 表示必输
0 表示可以逼平
1 表示能赢
-1 表示必输
0 表示可以逼平
样例输入
4
***
L**L
L**L***L
L*****L
***
L**L
L**L***L
L*****L
样例输出
0
-1
1
1
-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的,即是必输的状态。