HDU5973 - 2016 ACM-ICPC Dalian - C - Game of Taking Stones - (威佐夫博弈,牛顿法,JAVA高精度)

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/sdau20163942/article/details/82933639

题目链接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来实现。

牛顿法如下(见《数值分析》课本)

  1. 对于给定的正数C,应用牛顿法解二次方程。X^2-C=0;
  2. 可导出求开方值sqrt(C)的计算程序:x_k+1=1/2*(x_k+C/x_k);

例如求sqrt(115):

  1. 取初值x_0=10,对C=115按上式跌倒三次便可得到精度为1e-6的结果。
  2. 由于上面公式对于任意初始值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)));//保留小数点后120
	        pre=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);
			else
				System.out.println(1);
		}
		
		cin.close();
	}
}

 

猜你喜欢

转载自blog.csdn.net/sdau20163942/article/details/82933639
今日推荐