排成一条线的纸牌博弈问题

排成一条线的纸牌博弈问题

http://www.nowcoder.com/questionTerminal/19c98d950b3347d19f991d10bde12288

#include <vector>
#include <iostream>
using namespace std;
int win1(vector<int>& arr) {//使用标准二维dp
    int n = arr.size();
    vector<vector<int>> first(n, vector<int>(n, 0)); //first[i][j]表示在arr[i...j]上先手获得的最好分数
    vector<vector<int>> second(n, vector<int>(n, 0)); //second[i][j]表示在arr[i...j]上后手获得的最好分数
    for(int i = 0; i < n; i++) {
        first[i][i] = arr[i];
        for(int j = i-1; j >=0; j--) {
            //先手要么取左边的arr[j],要么取右边的aar[i],趣时主要考虑自己作为后手在剩下的局面上能拿多少分
            first[j][i] = max(arr[j] + second[j+1][i], arr[i] + second[j][i-1]);
            //这句我花了很大心思理解,为什么是min?因为后手是被动的,只能挑先手剩下的最坏情况
            second[j][i] = min(first[j+1][i], first[j][i-1]);
        }
    }
    return max(first[0][n-1], second[0][n-1]);
}

//参考:https://www.nowcoder.com/questionTerminal/19c98d950b3347d19f991d10bde12288?toCommentId=5976617
int win2(vector<int>& arr) {//使用滚动数组,压缩空间复杂度到O(n)
    int n = arr.size();
    vector<int> first(n, 0);
    vector<int> second(n, 0);
    for(int i = 0; i < n; i++) {
        first[i] = arr[i]; //first[i][i]
        second[i] = 0; // second[i][i] 很重要,一维时需要重置,容易遗漏
        for(int j = i - 1; j >= 0; j--) {
            int tmp = first[j]; //first[j][i-1],需要保存,因为一维时first[j]会覆盖它
            first[j] = max(arr[j] + second[j+1], arr[i] + second[j]);
            second[j] = min(first[j+1], tmp);
        }
    }
    return max(first[0], second[0]);
}

int main() {
    int n;
    cin >> n;
    vector<int> arr(n);
    for(int i = 0; i < n; i++) {
        cin >> arr[i];
    }
    //cout << win1(arr) << endl;
    cout << win2(arr) << endl;
    return 0;
}

全部评论

相关推荐

头像
04-26 15:00
已编辑
算法工程师
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务