1. 程式人生 > >題解——洛谷P2734 遊戲A Game 題解(區間DP)

題解——洛谷P2734 遊戲A Game 題解(區間DP)

表示 training 代碼 clas rain region str 所有 sample

題面

題目背景

有如下一個雙人遊戲:N(2 <= N <= 100)個正整數的序列放在一個遊戲平臺上,遊戲由玩家1開始,兩人輪流從序列的任意一端取一個數,取數後該數字被去掉並累加到本玩家的得分中,當數取盡時,遊戲結束。以最終得分多者為勝。

題目描述

編一個執行最優策略的程序,最優策略就是使玩家在與最好的對手對弈時,能得到的在當前情況下最大的可能的總分的策略。你的程序要始終為第二位玩家執行最優策略。

輸入輸出格式

輸入格式:

第一行: 正整數N, 表示序列中正整數的個數。

第二行至末尾: 用空格分隔的N個正整數(大小為1-200)。

輸出格式:

只有一行,用空格分隔的兩個整數: 依次為玩家一和玩家二最終的得分。

輸入輸出樣例

輸入樣例#1:
6 
4 7 2 9 5 2
輸出樣例#1:
18 11

說明

題目翻譯來自NOCOW。

USACO Training Section 3.3

題解

首先它看起來像是一道博弈論,但是仔細分析,就會發現它不過是要求第二個人取數的和值最大

所以是一道區間取數的DP(沒錯我瞄了眼題解

然後開始做題

蒟蒻的我還是naive的很,然後腦子一熱就寫下了以下的狀態轉移

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

簡直腦殘(霧)

因為這是兩個人取數,不是一個人拿數字,所以理所當然的就WA了

然後我們考慮到,在序列中,一個人拿完之後,另一個人會拿到其他的所有

所以讓\( dp[i][j] \)表示先手在區間\( \left [ i,j \right ] \)的最大值

狀態轉移方程就變成了

\( dp[i][j]=max(sum[i][j]-dp[i+1][j],sum[i][j]-dp[i][j-1]) \)

然後前綴和隨便搞一搞

A了QwQ

被這種題吊打,果然我還是太蒟蒻了

代碼

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace
std; int dp[111][111],a[111],sum[111],n; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]+=sum[i-1]+a[i]; for(int i=1;i<=n;i++) dp[i][i]=a[i]; for(int l=2;l<=n;l++) for(int i=1;i+l-1<=n;i++) dp[i][i+l-1]=sum[i+l-1]-sum[i-1]-min(dp[i+1][i+l-1],dp[i][i+l-2]); printf("%d %d",dp[1][n],sum[n]-dp[1][n]); return 0; }

題解——洛谷P2734 遊戲A Game 題解(區間DP)