紙牌博弈問題

2021-07-04 08:56:49 字數 1914 閱讀 3649

題目:有乙個整型陣列a,代表數值不同的紙牌排成一條線。玩家a和玩家b依次拿走每張紙牌,規定玩家a先拿,玩家b後拿,但是每個玩家每次只能拿走最左或最右的紙牌,玩家a和玩家b都絕頂聰明,他們總會採用最優策略。請返回最後獲勝者的分數。給定紙牌序列a及序列的大小n,請返回最後分數較高者得分數(相同則返回任意乙個分數)。

測試樣例:

[1,2,100,4],4

返回:101

解析:a和b都是絕頂聰明,他們每次拿元素時,肯定是按對自己最有力的方式拿。該題目先由最普通的遞迴解法,然後進行優化,到動態規劃。

遞迴方式,對陣列arr,元素數為n。

f(arr, l , r)表示對於陣列arr,元素從l到r,先拿可以達到的最大分數;

s(arr, l, r)表示對於陣列arr, 元素從l到r,後拿可以達到的最大分數。

對於f(arr, l, r),先拿時,有兩種拿法,拿第乙個arr[l],或最後乙個arr[r];如果拿arr[l],那麼剩餘的arr[l+1,....r]能拿到的最大分數為s(arr, l+1, r),分數為arr[l] +s(arr, l+1, r); 如果拿arr[r],剩餘的arr[l, ...r-1]能拿到的最大分數為s(arr, l, r-1),分數為arr[r] + s(arr, l, r-1),因為對於先拿後剩餘的陣列,當前人再拿的話是後拿的,然後取這兩種拿法較大的分數。

對於s(arr, l, r),如果前乙個人先拿了arr[l],則後拿的分數為f(arr, l+1, r),如果前乙個人先拿了arr[r],則後拿的分數為f(arr, l, r-1),因為對於剩餘的元素來說,你是先拿的,取兩種方式的較小值才是s的值。(為什麼取較小值,而不是較大值?因為a和b都是絕頂聰明人,你是在另乙個絕頂聰明人之後才拿的,他給你剩下的肯定是較壞的情況)

遞迴實現的方式如下,可以再進行動態規劃方式的優化,接下來再講。

/* 返回較大值 */

int max(int a, int b)

/* 返回較小值 */

int min(int a, int b)

/* 對陣列arr,從l到r元素,先拿的最大分數 */

int f(int arr, int l, int r)

return max(arr[l] + s(arr, l+1, r), arr[r] + s(arr, l, r-1));

}/* 對陣列arr,從l到r元素,後拿的最大分數 */

int s(int arr, int l, int r)

return min(f(arr, l+1, r), f(arr, l, r-1));

}int findwinnerscore(int arr, int l, int r)

態規劃定義了兩個表f和s,f[i][j]表示arr[i...j]先拿的最大分數,s[i][j]表示arr[i...j]後拿的最大分數。最終比較f[0][n-1]和s[0][n-1]的值,返回較大的即可。

在遍歷填寫兩個表之前,我們可以對錶進行初始化。初始化後,可以按列進行遍歷,行從最後乙個開始,因為每個f[i][j]和s[i][j]的值都是由f[i+1][j]、f[i][j-1]或s[i+1][j]、s[i][j-1]得到的。

動態規劃的**如下:

int dp(int arr, int n)

/* 初始化 */

f[0][0] = arr[0];

s[0][0] = 0;

f[n-1][n-1] = arr[n-1];

s[n-1][n-1] = 0;

for (i = 1; i < n; i++)

for (i = 0; i < n-1; i++)

for (j = 1; j < n; j++)

else}}

return max(f[0][n-1], s[0][n-1]);

}

紙牌博弈問題

題目 有乙個整型陣列a,代表數值不同的紙牌排成一條線。玩家a和玩家b依次拿走每張紙牌,規定玩家a先拿,玩家b後拿,但是每個玩家每次只能拿走最左或最右的紙牌,玩家a和玩家b都絕頂聰明,他們總會採用最優策略。請返回最後獲勝者的分數。給定紙牌序列a及序列的大小n,請返回最後分數較高者得分數 相同則返回任意...

紙牌博弈 改DP

這個題目刷過一次 沒記住位址 有一串紙牌 只能從紙牌兩邊抽取撲克,有兩名玩家,假設兩名玩家都絕頂聰明會選擇,會選擇最優的情況,抽取的紙牌面值累加為分數,求獲勝者的分數和。輸入 42 7 100 20 輸出 102 先思考抽牌的情況 從左邊抽 那麼第二個人就從剩下的部分抽 從右邊抽 由於兩個人都是絕頂...

排成一條線的紙牌博弈問題

問題描述 給定乙個整型陣列,代表數值不同的紙牌排成一條線。玩家a和玩家b依次拿走每張紙牌,規定玩家a先拿,玩家b後拿。但是每個玩家每次只能拿走最左或者最右的紙牌,玩家a和b都絕頂聰明,請返回最後獲勝者的分數。解答 定義乙個函式 func int arr 用來表示最優結果,那麼針對第乙個人是先拿第一張...