動態規劃題解D005 紙牌博弈

題目解讀

原題鏈接: 牛客網 2016校招真題在線編程

題目描述

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

輸入描述

[1,2,100,4],4

輸出描述

101

題意理解

這是一條博弈題,題目中說明了A、B兩個人不斷取牌來計分的過程。注意這裏有一個先手和後手轉換的關係。A、B兩個對象,既有做先手的時刻,又有做後手的時刻,比如對於序列1,2,100,4,在時刻1,對於該序列是A先手,而一旦A選取1後,在時刻2,對於序列2,100,4,A又變爲了後手,因爲此刻是由B來進行挑選。同理,B也有先手和後手的時刻。

算法分析

考慮到先手和後手的對應關係,我們設置兩個數據結構
First[a][b]:表示對於字符串num[a]-num[b]採用先手能夠取得的分數;
Second[a][b]:表示對於字符串num[a]-num[b]採用先手能夠取得的分數;
那麼First[a][b] = max(A[a]+S[a+1][b],A[b]+S[a][b-1]);
Second[a][b]=min(First[a+1][b],First[a][b-1])
有一個需要注意的地方在於,如何確定循環中變量的先後順序,
我自己的感覺是要根據狀態轉移方程來判斷:
比如現在我讓行代表a,而列代表b,則對於一個(a,b)來說,要想求得它,必須要先拿到(a+1,b)和(a,b-1)兩個座標,那麼從幾何角度來看,就是從左下角開始向右上角生成,所以對於a來說是要相減,而對於b來說是要相加。

代碼

class Cards {
public:
    int cardGame(vector<int> A, int n) {
        int **F = new int*[n];
        int **S = new int*[n];
        for(int i=0;i<n;i++){
            F[i]=new int[n];
            S[i]=new int[n];
        }
        for(int r=0;r<n;r++){
            F[r][r]=A[r];
            S[r][r]=0;
        }
        for(int r=0;r<n;r++){
            for(int l=r-1;l>=0;l--){
                F[l][r] = max(A[l]+S[l+1][r],A[r]+S[l][r-1]);
                S[l][r] = min(F[l+1][r],F[l][r-1]);
            }
        }
        int result = max(F[0][n-1],S[0][n-1]);
        delete[] F;
        delete[] S;
        return result;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章