poj2315足球游戏

这篇博客探讨了一种足球射门比赛的博弈问题,其中两名球员爱丽丝和鲍勃轮流射门,每次可以选择不超过M个足球,每个足球最大射程为L。问题转化为石子堆博弈,通过半加运算的异或操作确定胜负策略。最终,通过编程解决该问题,输出获胜者的名字。

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

问题描述:

爱丽丝和鲍勃都非常热爱足球,两人都是先锋。他们都擅长足球控制。一场足球比赛后的一天,他们进行了一场有趣的比赛,他们将足球直接射向球门。球门前有N个足球,他们轮流进行这场比赛。例如,如果轮到爱丽丝,爱丽丝可以选择一些足球(足球的数量必须等于或小于 M)并将它们射向前方。由于足球的质量不是很好,足球不是一个完整的球体,只能滚动其周长的整数倍。而且由于他们的摩擦力和力量的限制,他们无法将足球射出超过L厘米的距离。当然,他们知道足球的半径是 R 厘米。爱丽丝和鲍勃非常喜欢这个游戏。如果他们俩都拥有无限的智商和精准的射门技巧,你能猜出谁能赢得这场足球比赛吗?顺便说一句,虽然爱丽丝和鲍勃一样强壮,但爱丽丝是个女孩,所以她会先出手。

分析:题目大意是两名球员轮流从N个球中挑出不多于M个射门,每个球半径都是R,离球门S。每次只能踢出L以内的距离。进最后一个球者胜,求谁有必胜策略?我们发现对数据进行处理之后,题目等价于给出n堆石子,每堆石子中每次最多取k个石子,每次最多选取m个石子堆做操作的博弈问题,首先我们将每堆石子堆对k+1取模简化运算,取一堆石子上的石子的做法我们是对所有的石子堆的sg值进行xor运算得到sg值,xor又称为半加运算,只进行加法而不进位,对于选取m堆石子的博弈我们的xor则是对于m+1进制下的半加运算,所以我们按位计算这个sg值,模拟m+1进制下的半加运算即可得到答案。

输入:

输入由几个案例组成,每个案例包含两行。
对于每个测试用例,第一行包含 4 个整数 N、M、L 和 R(1 <= M <= N <= 30, 0 < L < 100000000, 0 < R < 10000),用一个空格分隔。N是足球的数量,M是一名球员一回合可以射出的最大足球数,L是一名球员可以射出的最大距离,R是足球的半径。
下一行包含 N 个数字,S(1), S(2), ..., S(N) (0 < S(i) < 100000000),它们描述了足球和球门之间的距离。

输出:

对于每种情况,输出都包含一行描述获胜者的姓名。

样本输入:

 

样本输出:

 程序代码:

#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int N=30;
const double PI=acos(-1.0);
int n,m,l,r,a[N],sg[N];
int dis(int s)                        //看能否进球
{
     return (int)(s/(2*PI*r))+1;
}
bool solve(){                        //博弈函数
    memset(sg,0,sizeof(sg));
    int k=dis(l);
    for(int i=0;i<n;i++)
      for(int j=0,g=dis(a[i])%k;sg[j]+=g&1,g;j++,g>>=1);
        for(int i=0;i<30;i++)
           if(sg[i]%(m+1))
               return 1;
    return 0;
}
int main(){
    while(~scanf("%d%d%d%d",&n,&m,&l,&r)){
        for(int i=0;i<n;i++)
             scanf("%d",&a[i]);
             puts(solve()?"Alice":"Bob");
    }
    return 0;
}

yjg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值