1. 程式人生 > >Game of Taking Stones HDU

Game of Taking Stones HDU

分類:威佐夫博弈+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");
		}
	}
}