[USACO3.3]遊戲 A Game
題目背景
有如下一個雙人遊戲:N(2 <= N <= 100)個正整數的序列放在一個遊戲平臺上,遊戲由玩家1開始,兩人輪流從序列的任意一端取一個數,取數後該數字被去掉並累加到本玩家的得分中,當數取盡時,遊戲結束。以最終得分多者爲勝。
題目描述
編一個執行最優策略的程序,最優策略就是使玩家在與最好的對手對弈時,能得到的在當前情況下最大的可能的總分的策略。你的程序要始終爲第二位玩家執行最優策略。
題目看上去像博弈論的題目,但是其實不是,是一道線性dp題,轉移方程比較難想;
dp[l][r] 表示區間 [l,r] 玩家能獲得的最大分數,那麼: dp[l][r]=sum[l,r]-min(dp[l+1][r],dp[l][r-1]);
運用到了一點貪心思維,dp[l+1][r]和dp[l][r-1]分別表示另一個玩家在該玩家拿完後的最大分數;減去它們的最小值,不就是該玩家能獲得的最大分數嗎?
代碼:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,LL>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=1100;
const int M=50100;
const int mod=1e9;
int n,dp[N][N],sum[N],a[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],sum[i]=sum[i-1]+a[i];
for(int i=1;i<=n;i++) dp[i][i]=a[i];
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
dp[i][j]=sum[j]-sum[i-1]-min(dp[i+1][j],dp[i][j-1]);
}
}
cout<<dp[1][n]<<" "<<sum[n]-dp[1][n]<<endl;
return 0;
}