hdu4111 成都现场赛A题

12 篇文章 0 订阅
/*
题意:有N堆石子,每堆石子有一个数目,现有两个人博弈,每个人每次可以进行两个操作中的一个:
1、从某堆拿掉一个石子(若某堆石子为0了,那么这堆就不存在了);2、合并两堆石子
没有操作的就输。问是哪个赢
思想:如果每堆石子数都大于1,那么最后结果肯定相当于所有的堆合并成一堆后,然后再一个一个拿掉的结果。
因为如果那种情况是赢的人一定会不断合并堆来确保他是赢的。又因为所有堆的石子数都大于1,所以输的人无法阻止他这么干。
而有些堆石子数等于1的话,就不一定是所有的合并的结果了,因为输的人可以直接把等于1的堆去掉,就破坏了结构
(合并相当于2步,去掉只需要1步)。
dp[i][j]表示有i个石子数为1的堆数,其它堆合并再取完的步数为j。若值为1则先取者胜,为0为先取者输
*/
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

int dp[55][55000];
int a[55];
int DP(int a,int b)
{
	if(dp[a][b]!=-1) return dp[a][b];
	if(b==1) return dp[a][b]=DP(a+1,0);//只剩一个单独的一,加入其它1中
	dp[a][b]=0;
	if(a>=1&&!DP(a-1,b))//直接去掉一个1
		dp[a][b]=1;
	if(a>=1&&b&&!DP(a-1,b+1))//将一个1合到其它数中
		dp[a][b]=1;
	if(a>=2&&((b&&!DP(a-2,b+3))||(b==0&&!DP(a-2,2))))//将2个1并起来
		dp[a][b]=1;
	if(b>=2&&!DP(a,b-1))//减小一
		dp[a][b]=1;
	return dp[a][b];
}
int main()
{
	memset(dp,-1,sizeof(dp));
	int t,test=1,n,i,j,k;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(j=0,k=0,i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			if(a[i]==1) j++;
			else k+=a[i]+1;//+1是因为要合并,多一步
		}
		if(k) k--;//合并的次数多算了一次
		DP(j,k);
		printf("Case #%d: ",test++);
		if(dp[j][k]) printf("Alice\n");
		else printf("Bob\n");
	}
	return 0;
}

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值