博弈的題目。123456各四張花色,遊戲開始時從中抽掉一些牌。每人一次抽取一張相加,和大於31者失敗。求必勝策略。
設定狀態表示爲行動結束時剩下的sum。假如每種牌無限制張數,那麼就等於搶七,必勝態爲0、7、14、21、28。
但是當給定一些牌的時候,只能搜索。類似記憶化搜索,注意:牌數量不同,節點的狀態也不同。
當搶到必勝態之後,上一個可以到達必勝態的節點一定是必敗態。以無限制撲克戰爲例,比如( 13 12 11 10 9 8 ) ->7 都是必敗態。假如你留給對方這樣的狀態,那麼對手就贏了。
而必勝態只有兩種情況:1.搶到0 2.下一個節點不可能是必勝態(對手無論如何都是必敗,你就是必勝)。比如14 ->?無論如何都不可能達到必勝態。
當加入不同程度限制的時候,上述兩法則依然成立。
試舉一例:最後一樣例,初始狀態爲7,留下撲克爲12346.
12346顯然是必敗態。5爲必勝態。7->5可以到達,即必敗態,留下7給對手的人必輸。
理論上所有博弈題目都是這兩個步驟。程序很簡單,但是理解起來挺費勁。我碼了那麼多字,卻發現自己知道的比之前更少。
#include <string>
char str[1000];
int card[7];
bool dfs ( int sum )
{
int i;
for ( i = 1; i <= 6; i ++ )
{
if ( card[i] && sum - i >= 0 )
{
card[i] --;
if ( dfs ( sum - i ) )
{
card[i] ++;
return false;
}
card[i] ++;
}
}
return true;
}
void proc ()
{
int i, sum = 31;
for ( i = 0; i < 7; i ++ )
card[i] = 4;
int turn;
int len = strlen ( str );
for ( i = 0, turn = 0; i < len; i ++, turn = 1 - turn )
{
sum -= str[i] - '0';
card[str[i] - '0'] --;
}
if ( sum > 0 )
if ( dfs ( sum ) )
turn = 1 - turn;
if ( sum == 0 )
turn = 1 - turn;
printf ( "%s %c ", str, 'A' + turn );
}
int main ()
{
//freopen ( "in.txt", "r", stdin );
while ( scanf ( "%s", str ) != EOF )
{
proc ();
}
return 0;
}