ZOJ 1827 The Game of 31

博弈的題目。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 <cstdio>
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章