1. 程式人生 > >從數組兩頭抽取元素遊戲

從數組兩頭抽取元素遊戲

使用 給定 必須 這一 最大值 優化 空間 時間 -1

給定一個數組,玩家A,B每次從數組頭或尾取數,且只能從頭尾取。假定A,B都絕頂聰明,均采取最優策略,判斷A先手的情況下,A是否能夠獲勝。

分析: f(i, j) 表示 在arr[i~j]中A 先手時能夠獲得的最大分數,s(i, j) 表示 A後手時能夠獲得的最大分數。

首先分析f(i, j)。 A可先取arr[i], 取完後剩余arr[i+1, j]。此時相當於A後手在[i+1, j]的情況了。

也可先取arr[j], 取完後剩余arr[i, j - 1]。 此時相當於A後手在[i, j -1]的情況了。

則 f(i, j) = max{arr[i] + s(i+1, j), arr[j] + s(i, j-1)}

再分析s(i, j)。B可先取arr[i] 或 arr[j] 。取完後相當於A先手的情況了。只是在這種情況下,B會留下最差解。

s(i, j) = min{arr[i] + f(i+1, j), arr[j] + f(i, j-1)};

故可生成兩個二維矩陣。代碼如下:

邊界條件:

f[j][j] = arr[j]; 因為只有一個數,先手必取這個數。
public static int win2(int[] arr) {
		if (arr == null || arr.length == 0) {
			return 0;
		}
		int[][] f = new int[arr.length][arr.length];
		int[][] s = new int[arr.length][arr.length];
		for (int j = 0; j < arr.length; j++) {
			f[j][j] = arr[j];
			for (int i = j - 1; i >= 0; i--) {
				f[i][j] = Math.max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);
				s[i][j] = Math.min(f[i + 1][j], f[i][j - 1]);
			}
		}
		return f[0][arr.length - 1], s[0][arr.length - 1];
	}

  

上述方法時間復雜度O(N2),用到了兩個二維數組。可以在空間復雜度上稍微優化一下,只使用1個二維數組。

用dp[i][j]表示在arr[i~j]中A先手的情況能取得的最大分數。則A的這一次先手與下一次先手有4種可能:

1. A 取 arr[i], B 取 arr[j] , 剩下[i+1, j-1]

2. A 取 arr[i], B 取arr[i+1], 剩下[i+2, j]

3. A 取 arr[j], B 取arr[i], 剩下[i+1, j-1]

4. A 取arr[j] , B 取arr[j-1], 剩下[i, j-2]

前兩種情況取最小情況,後兩種情況取最小情況,然後取最大值。其實就是綜合之前的情況。

邊界條件:

i == j時,就是取arr[i]; 同時,此種情況必須保證j >= i +2, 即至少有3個數。代碼如下:

public  static int win1(int[] arr){
		if(arr == null || arr.length == 0)
			return 0;
		
		int len = arr.length;
		int[][] dp = new int[len][len];
		int part1, part2, part3, part4;
		
		for(int i = 0; i < len; i++)
			dp[i][i] = arr[i];
		
		for(int i = len - 1; i >= 0; i--)
			for(int j = i+1; j < len; j++){
				if( j >= i+2 ){
					part1 = ( i <= len -3 ? (arr[i] + dp[i+2][j]) : 0 );
					part2 =  ((i <= len -2 && j >= 1) ? (arr[i] +dp[i+1][j]) : 0);
					part3 = (j >= 2 ? (arr[j] + dp[i][j-2]) : 0);
					part4 =  ((j >= 1 && i <= len-2) ? (arr[j] + dp[i+1][j-1]) : 0);
				
					dp[i][j] = Math.max(Math.min(part1, part2), Math.min(part3, part4));
				}else
					dp[i][j] = Math.max(arr[i], arr[j]);
			}
		
		return dp[0][len-1];
	}

  

從數組兩頭抽取元素遊戲