問題描述
小明常常玩 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;
}