Triangle War--POJ 1085
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;
}