H、Playing games

本文介绍了一个基于博弈论的游戏策略问题,玩家需要选择最多数量的石堆以确保在游戏中获胜。通过计算石堆数量的异或和并寻找最小移除数量使异或和为0的方法来解决。文章提供了一种解决方案,并附带了示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Niuniu likes playing games. He has n piles of stones. The i-th pile has ai stones. He wants to play with his good friend, UinUin. Niuniu can choose some piles out of the n piles. They will play with the chosen piles of stones. UinUin takes the first move. They take turns removing at least one stone from one chosen pile. The player who removes the last stone from the chosen piles wins the game. Niuniu wants to choose the maximum number of piles so that he can make sure he wins the game. Can you help Niuniu choose the piles?
 
输入描述: The first line contains one integer n (1 ≤ n ≤ 500000), which means the number of piles. The second line describes the piles, containing n non-negative integers, a1 a2 … an, separated by a space. The integers are less than or equal to 500000.
 
输出描述: Print a single line with one number, which is the maximum number of piles Niuniu can choose to make sure he wins. If Niuniu cannot always win whatever piles he chooses, print 0.

示例 1

输入

8 1 9 2 6 0 8 1 7

输出

7

 

学过博弈论之后可以推得此种取法的每堆的sg函数值等于该堆的石子数,且要使后手赢,因此该题结果就变为找最大的堆数让这些堆得的异或和等于0;

以下是我个人的处理方法:

先求出总的异或和然后在找出最少可以去掉多少堆,

构造一个循环:

 

 

节点表示堆得石子数目,注意异或两个相同的数不会影响结果,所以在为循环记录石子数目时,相同的石子数目只用记录一次。

在处理减少某堆时,在异或结果上可以异或该堆得数目。每次选择循环的一个节点开始,然后挑选出,经过节点数目最少的使异或结果为0的节点数目该数目就是最少可以去掉的堆数。

 

#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=5000005;
int a[500005];
int q;
int x[500005];
int vis[500005]={0};
int ans=maxn; 
int main()
{
	int n;
	scanf("%d",&n);
	int sum=0;
	int k=0;
	for(int i=0;i<n;i++)
	{
		scanf("%d",&q);
		sum^=q;
		if(vis[q]==0)
		{
			a[k++]=q;
		}
		vis[q]=1;
	}
	if(sum==0)
	printf("%d",n);
	else
	{
		for(int i=0;i<k;i++)//构造一个环 
		{
			x[a[i]]=a[i+1];
		}
		x[a[k-1]]=a[0];
		for(int i=0;i<k;i++)//选一个环的节点开始
		{
			int cnt=0;//去掉的堆数;
			int j=a[i];
			int xo_r=sum; 
			while(xo_r!=0)
			{
				xo_r^=x[j];
				cnt++;
				j=x[j];
				if(j==a[i])
				break;
			}
			ans=min(ans,cnt);
		}
		printf("%d",n-ans);
	}
 } //此代码没有提交,只是个思路的展示,能否ac靠读者本人咯

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值