ICPC North America Qualifier Contest 2015 E. Cutting Brownies 不公平组合游戏,分析DP。(不能SG)

由于是不公平组合游戏,所以不能用SG函数。

但我们可以分析然后DP。

考虑怎么切是最优解。

对于H先手,切一刀后,会让(x,y)变成  (k,y)(x-k,y),即让y可以切的地方乘2.

所以每次尽量选择y小的切,且每次尽量选x/2且,(这样y切的时候能让H可切的地方尽量变多)

 

对于H先手,切一刀后,变成了(x/2,y),(x/2+(x&1),y).

如果这两个局面都是V先手必败,那么H肯定必胜。

但如果只有一个局面V先手必败会是什么情况呢?(即一个局面V先手必胜,一个局面V先手必败)

考虑V先手必胜的局面,那么肯定是(x/2,y)这个局面(因为这个局面,H可切的地方相对少一点)。

那么这个局面V必胜,V可以一直切这个局面。(一旦H去切另外一个局面,即(x/2+(x&1),y),那么,这个局面必然变成2个V必胜的局面:令z=x/2+(x&1) ;

( z/2,y),( z/2+z&1,y);

(因为z/2一定小于等于z-1,所以切的两个局面的X的值一定都小于x/2,且Y都等于y,即相对于刚才V先手必胜的局面,H可切的变少,V可切的不变。则这两个局面一定都是V先手必胜)

所以H只能跟V对切第一个局面(x/2,y)。

但这个局面是V必胜,则:H最后无处可切,只能切第二个局面,还是V必胜。

综上所述:

对于H先手,只有切一刀产生的2个局面都能使V必败,H才能必胜。

V同理。

有了这个结论,就可以用线性DP进行递推了。

dp[i][j][0],  i,j这个状态,H/V先手是否必胜

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
int dp[550][550][2];//i,j,局面,H/V先手是否必胜 
int vs[550];
void gt_sg() 
{
	int n=500;
	dp[1][1][0]=dp[1][1][1]=0;
	for(int i=1;i<=n;i++)//i行 
	for(int j=1;j<=n;j++)//j列 
	{
		if(i+j==2)continue;
		//0
		int tp=0;
		for(int k=1;k<i;k++)
			tp|=!(dp[k][j][0]||dp[i-k][j][0]);//是否有让后手必败的局面 
		dp[i][j][1]=tp;
		//1
		tp=0;
		for(int k=1;k<j;k++)
			tp|=!(dp[i][k][1]||dp[i][j-k][1]);//是否有让后手必败的局面 
		dp[i][j][0]=tp;
	}
} 
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	gt_sg();
  	int n;
  	cin>>n;
  	for(int i=1;i<=n;i++)
  	{
  		int a,b;
  		char s[111];
  		cin>>a>>b>>s;
  		if(s[0]=='H')
  		{
  			if(dp[a][b][0]==0)cout<<"Harry cannot win"<<endl;
  			else cout<<"Harry can win"<<endl;
		}
		else
		{
			if(dp[a][b][1]==0)cout<<"Vicky cannot win"<<endl;
  			else cout<<"Vicky can win"<<endl;
		}
	  }
	return 0;
}

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值