題目:有乙個整型陣列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都是絕頂聰明人,你是在另乙個絕頂聰明人之後才拿的,他給你剩下的肯定是較壞的情況)
遞迴實現的方式如下,可以再進行動態規劃方式的優化,接下來再講。
[cpp]view plain
copy
/* 返回較大值 */
intmax(
inta,
intb)
/* 返回較小值 */
intmin(
inta,
intb)
/* 對陣列arr,從l到r元素,先拿的最大分數 */
intf(
intarr,
intl,
intr)
return
max(arr[l] + s(arr, l+1, r), arr[r] + s(arr, l, r-1));
} /* 對陣列arr,從l到r元素,後拿的最大分數 */
ints(
intarr,
intl,
intr)
return
min(f(arr, l+1, r), f(arr, l, r-1));
} int
findwinnerscore(
intarr,
intl,
intr)
動態規劃定義了兩個表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]得到的。
動態規劃的**如下:
[cpp]view plain
copy
intdp(
intarr,
intn)
/* 初始化 */
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 用來表示最優結果,那麼針對第乙個人是先拿第一張...