1、题目类型:博弈、DP。
2、解题思路:(1)构建18条边、9个三角形分别由那三条边组成;(2)模拟输入的残局,并记录A、B获得三角形的差值,中间利用player保持A、B主动权的变换;(3)DP递归剩余情况,寻找player到最后的单步最有情况;(4)判断最终的最大差值MAX,正负即A、B博弈的结果。
3、注意事项:注意构造三角形三边是对应的16进制表示;DP递归过程中注意dp[]的更新。
4、参考博客:http://blog.csdn.net/bobten2008/archive/2009/08/25/4484005.aspx
5、实现方法:
#include < iostream >
#include < algorithm >
using namespace std;
#define MIN -10
int line[ 18 ][ 2 ] = {
{ 1 , 2 },{ 1 , 3 },{ 2 , 3 },
{ 2 , 4 },{ 2 , 5 },{ 3 , 5 },
{ 3 , 6 },{ 4 , 5 },{ 5 , 6 },
{ 4 , 7 },{ 4 , 8 },{ 5 , 8 },
{ 5 , 9 },{ 6 , 9 },{ 6 , 10 },
{ 7 , 8 },{ 8 , 9 },{ 9 , 10 }
};
int tri[ 9 ][ 3 ] = {
{ 0x01 , 0x02 , 0x04 },
{ 0x04 , 0x10 , 0x20 },
{ 0x08 , 0x10 , 0x80 },
{ 0x20 , 0x40 , 0x100 },
{ 0x200 , 0x400 , 0x8000 },
{ 0x80 , 0x400 , 0x800 },
{ 0x800 , 0x1000 , 0x10000 },
{ 0x100 , 0x1000 , 0x2000 },
{ 0x2000 , 0x4000 , 0x20000 }
};
int dp[ 600000 ],pow[ 18 ];
int m,player,state,x,y;
// 寻找当前状况下,是否可以构成三角形
int Cal( int pos, int state)
{
int i,j,flag,t, get = 0 ;
for (i = 0 ;i < 9 ;i ++ )
{
flag = 0 ;t = 3 ;
for (j = 0 ;j < 3 ;j ++ )
{
if (pow[pos] & tri[i][j])
t = j;
else if (state & tri[i][j])
flag ++ ;
}
if (t == 3 )
continue ;
if (flag == 2 )
++ get ;
}
return get ;
}
int DP( int state)
{
if (dp[state] != MIN)
return dp[state];
int i,t,MAX = MIN;
for (i = 0 ;i < 18 ;i ++ )
{
if ( ! (state & pow[i]))
{
t = Cal(i,state);
t += (t > 0 ? 1 : - 1 ) * DP(state | pow[i]);
MAX = (t > MAX ? t:MAX);
}
}
dp[state] = MAX;
return MAX;
}
void Solve( int ca)
{
int i,j,t,cnt = 0 ;
cin >> m;
player = 1 ;
state = 0 ;
for (i = 0 ;i < m;i ++ )
{
cin >> x >> y;
for (j = 0 ;j < 18 ;j ++ )
{
if (x == line[j][ 0 ] && y == line[j][ 1 ])
{
t = Cal(j,state);
state |= pow[j];
break ;
}
}
if (t)
cnt += player * t;
else
player *=- 1 ;
}
cout << " Game " << ca << " : " << ((cnt + player * DP(state)) > 0 ? ' A ' : ' B ' ) << " wins. " << endl;
}
int main()
{
int i,T,tmp = 1 ;
cin >> T;
for (i = 0 ;i < 18 ;i ++ )
{
pow[i] = tmp;
tmp *= 2 ;
}
fill(dp,dp + 600000 , - 10 );
dp[ 0x3FFFF ] = 0 ;
for (i = 1 ;i <= T;i ++ )
{
Solve(i);
}
return 0 ;
}