题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5973
题意:给出两堆石头的个数a和b(a,b小于等于10^100),两个人轮流拿石头,两个人轮流从某一堆或同时从两堆中取同样多的任意数量的物品,最后取光者得胜。
解析:标准威佐夫博弈,只不过这里给的数很大,所以用java大数来做。
而用JAVA大数来做面临一个问题:BigInteger没有sqrt函数,没法求sqrt(5)。这里用牛顿法来求一个精度较高的sqrt(5),操作用JAVA的BigDecimal来实现。
牛顿法如下(见《数值分析》课本):
- 对于给定的正数C,应用牛顿法解二次方程。X^2-C=0;
- 可导出求开方值sqrt(C)的计算程序:x_k+1=1/2*(x_k+C/x_k);
例如求sqrt(115):
- 取初值x_0=10,对C=115按上式跌倒三次便可得到精度为1e-6的结果。
- 由于上面公式对于任意初始值x_0均收敛,并且收敛的速度很快,因此我们可取确定的初值如x_0=1编制通用程序。用这个通用程序求sqrt(115),也只要迭代7次便得到了上面的结果10.723805.
JAVA中BigDecimal的一些操作如下:
初始化:
- BigDecimal的两种常用构造方法:
- ①.BigDecimal b = new BigDecimal("2.3");
- ②.BigDecimal b = BigDecimal.valueOf(2.3);
- 用方法一时不建议用double类型作为实参,因为会产生较大误差(由于二进制缘故)。
- 要开根号的本来就是double类型时最好用方法②,或可将double用Double.toString(double)转化为String再用方法①
BigDecimal的除法BigDecimal.divide():
- 其实divide方法有可以传三个参数:public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
- 第一参数表示除数, 第二个参数表示小数点后保留位数,
- 第三个参数表示舍入模式,只有在作除法运算或四舍五入时才用到舍入模式,有下面这几种:
ROUND_CEILING //向正无穷方向舍入
ROUND_DOWN //向零方向舍入
ROUND_FLOOR //向负无穷方向舍入
ROUND_HALF_DOWN //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5
ROUND_HALF_EVEN //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用ROUND_HALF_UP,如果是偶数,使用ROUND_HALF_DOWN
ROUND_HALF_UP //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6
ROUND_UNNECESSARY //计算结果是精确的,不需要舍入模式
ROUND_UP //向远离0的方向舍入
代码(178ms):
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;public class Main {static BigDecimal NewtonSqrt(double inC)//求高精度sqrt(inC){BigDecimal pre=BigDecimal.valueOf(1);BigDecimal now=null;BigDecimal C=BigDecimal.valueOf(inC);BigDecimal half=BigDecimal.valueOf(0.5);for(int i=1;i<=100;i++)//迭代100次{now=half.multiply(pre.add(C.divide(pre,120,BigDecimal.ROUND_HALF_DOWN)));//保留小数点后120pre=now;}return now;}public static void main(String[] args) {Scanner cin=new Scanner(System.in);BigDecimal sqrt5=NewtonSqrt(5.0);//System.out.println(sqrt5);BigInteger a,b;while(cin.hasNext()){a=cin.nextBigInteger();b=cin.nextBigInteger();if(a.compareTo(b)>0){BigInteger temp=a;a=b;b=temp;}String strk=b.subtract(a).toString();BigDecimal k=new BigDecimal(strk);BigDecimal x=sqrt5.add(BigDecimal.valueOf(1)).multiply(BigDecimal.valueOf(0.5));BigDecimal t=k.multiply(x).add(k);BigInteger bt=t.toBigInteger();//BigDecimal的小数部分将被丢弃if(bt.equals(b))System.out.println(0);elseSystem.out.println(1);}cin.close();}
}