dp基礎之博弈型和區間型結合輪流取數字

2021-09-01 18:20:37 字數 2649 閱讀 2294

問題分析:

這是一道博弈型dp,其實質上是區間型dp,目標是讓自己拿到的數字和不必對手小

設己方數字和是a,對方是b,目標是a>=b,等價於a-b>=0

也就是說,如果兩人都存著自己與對手的數字和之差,sa = a-b,sb = b-a,先手目標是讓sa最大化,後手目標讓sb最大化

當一方x面對剩下的數字時,他的目標就是最大化sx = x-y,當x取走乙個數字m後,對手y此時也變成先手,sy = y-x

對於x來說

sx = -sy+m = m-sy

m是當前要取的數字,sy是對手的數字和

現在x有兩種選擇,取序列a的頭或者尾,因為是最優策略,x選取的m = max、

case1:如果x取的是a[0],則y面對的是a[1],...,a[n-1],則y的目標是最大化sy,則x想要最大化sx = -sy+a[0] = a[0]-sy

case2:如果x取走的是a[n-1],則y面對的是a[0],...,a[n-2],則y的目標是最大化sy',則x想要最大化sx' = -sy'+a[n-1] = a[n-1]-sy'

當y面對x取走乙個數字後,此時y是先手,他的目標同樣是最大化sy,但此時y面對的序列是a[1],...,a[n-1]或者是

a[0],...,a[n-2]

子問題:設f[i][j]表示先手面對序列a[i][j]時能得到的與對手的數字差。

f[i][j] = max

max只有乙個數字a[i]時,己方得到數字a[i],對方沒有數字了,得0,數字差為a[i]

f[i][i] = a[i] (i = 0,...,n-1)

計算順序:

序列長度1:f[0][0],f[1][1],......,f[n-1][n-1]

序列長度2:f[0][1],f[1][2],...,f[n-2][n-1]..

.序列長度n-1:f[0][n-2],f[1][n-1]

序列長度n:f[0][n-1]

答案:f[0][n-1]>=0,則返回true否則返回false

時間和空間複雜度都是o(n^2),空間複雜度可以優化到o(n)

**及注釋如下:

def take_coins_inturn(a):

n = len(a)

if n == 0:

return true

f = [[0 for i in range(n)] for j in range(n)]

#初始化f[i][i] = a[i]

#長度1

for i in range(n):

f[i][i] = a[i]

#長度2,..n

for l in range(2,n+1):

for i in range(0,n-l+1):

j = i+l-1

#f[i][j] = max

f[i][j]= max(a[i]-f[i+1][j] , a[j]-f[i][j-1])

#只要f[0][n-1]大於等於0,說明先手必勝,否則先手必輸

return true if f[0][n-1] >= 0 else false

a = [1,5,233,7]

print(take_coins_inturn(a))

#結果:true

優化空間解釋:

本來要計算矩陣f是n*n的,計算順序是從f[i][i]組成的對角線開始,向右上計算過去,和dp基礎之最長回文子串裡的優化空間解釋圖一樣

每次計算f[i][j]時,和本行的f[i][j-1]、下一行的f[i+1][j]有關(只和f[i][j]左邊乙個數和下邊乙個數有關),且算完f[i][j]時,

f[i][j-1](f[i][j]左邊的那個數)不會再用到,因此,f[i][j]直接覆蓋f[i][j-1](左邊那個數)。壓縮到一行就是新計算出來的f[i]覆蓋到原來的f[i]

**及注釋如下:

def take_coins_inturn(a):

n = len(a)

if n == 0:

return true

f = [0 for i in range(n)]

#初始化f[i][i] = a[i]

#長度1

for i in range(n):

f[i] = a[i]

#長度2,..n

for l in range(2,n+1):

for i in range(0,n-l+1):

j = i+l-1

#f[i][j] = max

f[i]= max(a[i]-f[i+1] , a[j]-f[i])

#只要f[0][n-1]大於等於0,說明先手必勝,否則先手必輸

return true if f[0] >= 0 else false

a = [1,5,233,7]

print(take_coins_inturn(a))

#結果:true

dp基礎之博弈型取石子

問題分析 要求面對n個石子,是否先手必勝 需要知道面對n 1和n 2個石子,是否先手必勝 子問題 設f i 表示面對i個石子,是否先手必勝 f i true false f i true f i 1 false and f i 2 false 拿一顆石子或兩顆石子都輸 true f i 1 fals...

dp基礎之劃分型劃分最小劃分次數

確定狀態 最優策略中最後一段回文串是s j.n 1 需要知道s前j個字元 0.j 1 最少可以劃分成幾個回文串 子問題 設 s前i個字元 0.i 1 最少可以劃分成f i 個回文串 f i min 初始條件 f 0 0,前0個即空串是0 計算順序 f 0 f n 判斷回文串 分為奇數長度回文串和偶數...

dp基礎之雙序列型子串出現次數

問題分析 可以用類似於最長公共子串的思路。問b在a中出現的次數,考慮最後乙個字元b n 1 和a m 1 case1 如果b n 1 a m 1 則考慮b 0,n 2 在a 0,m 2 出現多少次 case2 如果b n 1 a m 1 則考慮b 0,n 1 在a 0,m 2 出現多少次 子問題 原...