題解——洛谷P2734 遊戲A Game 題解(區間DP)
阿新 • • 發佈:2018-09-02
表示 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 namespacestd; 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)