C - Game of Taking Stones HDU - 5973 (威佐夫博弈+Java的高精度)

C - Game of Taking Stones HDU - 5973

分类:威佐夫博弈+Java的高精度

2018TYUT秋季ACM模拟赛(13)2016大连

题意:给你两个石堆的石头数量,两个人轮流拿,两人轮流从任意一堆取至少一个或者从两堆取同样多的物品。问你先手获胜还是后手胜。

思路:二分求出sqrt(5),计算(b>a)(b-a)*(sqrt(5)+1)/2

威佐夫博弈:有两堆各若干个物品,两个人轮流从任一堆取至少一个或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

结论:给出的两堆石子(a,b)当(b>a)(b-a)*(sqrt(5)+1)/2==a 时先手失败。

两个人如果都采用正确操作,那么面对非奇异局势,先拿者必胜;反之,则后拿者取胜。

那么任给一个局势(a,b),怎样判断它是不是奇异局势呢?我们有如下公式:

ak =[k(1+√5)/2],bk= ak + k (k=0,1,2,...n 方括号表示取整函数)

奇妙的是其中出现了黄金分割数(1+√5)/2 = 1.618...因此,由ak,bk组成的矩形近似为黄金矩形,由于2/(1+√5)=(√5-1)/2,可以先求出j=[a(√5-1)/2],若a=[j(1+√5)/2],那么a = aj,bj = aj + j,若不等于,那么a = aj+1,b = aj + j + 1,若都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇到奇异局势。

下面来看看威佐夫博弈常见的三类问题:(详情见博客)

1)给你一个局面,让你求是先手输赢。

有了上面的分析,那么这个问题应该不难解决。首先求出差值,差值 * 1.618 == 最小值 的话后手赢,否则先手赢。(注意这里的1.618==(sqrt(5)+1)/2,否则精度要求高的题目会错)

2)给你一个局面,让你求先手输赢,假设先手赢的话输出他第一次的取法。

       首先讨论在两边同时取的情况,很明显两边同时取的话,不论怎样取他的差值是不会变的,那么我们可以根据差值计算出其中的小的值,然后加上差值就是大的一个值,当然能取的条件是求出的最小的值不能大于其中小的一堆的石子数目。假如在一堆中取的话,可以取任意一堆,那么其差值也是不定的,但是我们可以枚举差值,差值范围是0 --- 大的石子数目,然后根据上面的理论判断满足条件的话就是一种合理的取法。

java的知识:1、ctrl+shift+o---加包  ctrl +shift+f---调整格式  2、setScale(0, BigDecimal.ROUND_DOWN);设置精度

3、Scanner cin = new Scanner(System.in);while (cin.hasNext()) {}相当于c/c++中的while(cin>>n){}

import java.math.BigDecimal;
import java.util.Scanner;
//ctrl+shift+o---加包  ctrl +shift+f---调整格式 
public class Main {
	@SuppressWarnings("deprecation")
	public static void main(String[] ar) {
		Scanner cin = new Scanner(System.in);
		BigDecimal two = new BigDecimal(2);
		BigDecimal three = new BigDecimal(3);
		BigDecimal five = new BigDecimal(5);
		// 求sqrt(5)
		BigDecimal l = two, r = three;
		for (int i = 0; i < 500; i++) {
			BigDecimal mid = l.add(r).divide(two);
			if (mid.multiply(mid).compareTo(five) < 0)
				l = mid;
			else
				r = mid;
		}

		BigDecimal miao;// =l.add(r).divide(two);
		miao = l.add(new BigDecimal(1)).divide(two);
		// System.out.println(miao);
		while (cin.hasNext()) {
			BigDecimal a = cin.nextBigDecimal();
			BigDecimal b = cin.nextBigDecimal();
			if (a.compareTo(b) > 0) {
				BigDecimal c = a;
				a = b;
				b = c;
			}

			a = a.setScale(0, BigDecimal.ROUND_DOWN);
			b = b.subtract(a).multiply(miao);
			b = b.setScale(0, BigDecimal.ROUND_DOWN);
			// String x=a.toString();
			// String y=b.toString();
			if (a.compareTo(b) == 0)
				System.out.println("0");
			else
				System.out.println("1");
		}
	}
}

 

你可能感兴趣的:(2018ACM模拟赛集训)