1. 程式人生 > >UVa UVA 10891 Game of Sum (區間DP)

UVa UVA 10891 Game of Sum (區間DP)

/**
*      挺水的區間DP
*   dp[i][j] 表示該輪選手在還剩[i,j]的數中按規則選取所能得到的最大收益
*   最大收益也就是相對於當前選手最優決策後在區間[i,j]中使得兩選手的差值最大。
*   這樣dp[1][n]其實就是所要的答案。
*     如何求dp[1][n],其實就是個區間dp,從小範圍算起到最後1-n範圍。
*   再用個sum[n]陣列記錄前n項和,方便求區間[i,j]的和。
*   具體狀態轉移方程看程式碼,和普通的區間dp一樣,列舉z = i->j 如何根據遊戲規則取最大值 
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <algorithm>
#define DEBUG 0
#define INF 0x7fffffff
#define MAXN 105


typedef long long LL;
using namespace std;

int n, sum[MAXN], dp[MAXN][MAXN];

void dp_func()
{
    for(int k = 2; k <= n; k ++)
    {
        for(int i = 1; i <= n - k + 1; i ++)
        {
            int j = i + k - 1, curMax = -INF, ans;
            for(int z = i; z <= j; z ++)
            {
                int cur = sum[z] - sum[i-1] - dp[z+1][j];
                if(cur > curMax) {
                    curMax = cur;
                }
            }
            for(int z = j; z >= i; z --)
            {
                int cur = sum[j] - sum[z-1] - dp[i][z-1];
                if(cur > curMax)
                    curMax = cur;
            }
            dp[i][j] = curMax;
        }
    }

    cout << dp[1][n] << endl;
}

int main()
{
    while(cin >> n && n)
    {
        sum[0] = 0;
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i ++)
        {
            cin >> dp[i][i];
            sum[i] = sum[i-1] + dp[i][i];
        }
        dp_func();
    }
    return 0;
}