[hdu 5973 Game of Taking Stones] Wythoff Game+大数运算

本文介绍了一种解决大规模数据WythoffGame问题的方法,通过使用Java的BigDecimal类进行精确计算,避免了传统浮点数运算带来的误差。特别地,文章详细解释了如何手动实现平方根计算来确定游戏胜负。

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

[hdu 5973 Game of Taking Stones] Wythoff Game+大数运算

题目链接[hdu 5973 Game of Taking Stones]
类似题目[51Nod 1185 威佐夫游戏 V2]
题意描述:有2堆石子。两个人轮流拿。每次可以从一堆中取任意个或从2堆中取相同数量的石子,但不可不取。拿到最后1颗石子的人获胜。假设两个人都按照最优的策略取石子。给出2堆石子的数量,问先手是否能赢得比赛。 每堆石子的大小 10100
解题思路:典型的Wythoff Game[威佐夫博弈],满足黄金分割。

根据Wythoff 博弈定理:当且仅当 a=k5+12,b=a+k 时,先手失败;否则后手失败。

由于题目给定的石子数目巨大,所以不能用浮点数直接进行运算。在我的另外一篇博客《 [51Nod 1185 威佐夫游戏 V2]Wythoff Game+乘法模拟 》中,石子范围是 1018 , 我采用的是乘法模拟的方法。
在这个题目里面数据更大。乘法模拟起来就麻烦得多了。所以不妨直接用Java搞。关键是算 5 。Java的BigDemical类中没有开根号的函数。需要自己手写二分实现开根号。


tips:5+12=1.6180339887498948482045868343656... ,黄金分割率就是 0.6180339887498948482045868343656...

import java.math.BigDecimal;
import java.util.Scanner;

public class Main {
    static BigDecimal sqrt_five, G;
    static BigDecimal two, five;
    public static void init() {
        two = new BigDecimal(2);
        five = new BigDecimal(5);
        BigDecimal low, high, mid;
        low = new BigDecimal(0);
        high = new BigDecimal(5);
        mid = new BigDecimal(0);
        for(int i = 0; i < 1000; i++) {
            mid = low.add(high).divide(two);
            if(mid.multiply(mid).compareTo(five) > 0) high = mid;
            else low = mid;
        }
        sqrt_five = mid;
        // G = (sqrt(5) + 1) / 2;
        G = sqrt_five.add(BigDecimal.ONE).divide(two);
    }

    public static void main(String[] argv) {
        BigDecimal a, b, c, left, right;
        init();
        Scanner input = new Scanner(System.in);
        while (input.hasNext()) {
            a = input.nextBigDecimal();
            b = input.nextBigDecimal();
            if (a.compareTo(b) > 0) {
                c = a;
                a = b;
                b = c;
            }
            left = b.subtract(a).multiply(G);
            right = a;
            // 向下取整。统一精度。
            left = left.setScale(0, BigDecimal.ROUND_DOWN);
            right = right.setScale(0, BigDecimal.ROUND_DOWN);

            if(left.compareTo(right) == 0) System.out.println("0");
            else System.out.println("1");
        }
        return;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值