博弈的题目。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;
}
#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;
}