取數遊戲(博弈+動規)
阿新 • • 發佈:2019-02-05
題目描述
有如下一個雙人遊戲:N個正整數的序列放在一個遊戲平臺上,兩人輪流從序列的兩端取數,每次有數字被一個玩家取走後,這個數字被從序列中去掉並累加到取走該數的玩家的得分中,當數取盡時,遊戲結束。以最終得分多者為勝。
編一個執行最優策略的程式,最優策略就是使自己能得到在當前情況下最大的可能的總分的策略。你的程式要始終為兩位玩家執行最優策略。
輸入第1行包括一個正整數N(2≤N≤100), 表示序列中正整數的個數。輸入第2行包含用空格分隔的N個正整數(1≤所有正整數≤200)。
只有一行,用空格分隔的兩個整數: 依次為先取數玩家和後取數玩家的最終得分。
樣例輸入複製
6 4 7 2 9 5 2
樣例輸出複製
18 11
sum[i][j]表示從i位到j位所有的和,dp[i][j]表示從i位到j位使自身取到的所有值的最大和
想一下,先手要取掉兩端中的一個值,此時無論先取者還是後取者都希望自己取的是最優的。
何為最優?
都保證自己會取得保證取完後總和相對大的,如何表示?
對於先手而言,
先取左邊還是右邊?當先手取完,就輪到後手去,後手一定會選擇當前能令他得到最大分數的策略,其實當先手在[x, y]區間兩端取走一個數,那麼後手面臨兩個狀態[x+1, y]和[x, y-1],先手想要取得最大值,一定會想讓後手取這兩種狀態中的較小值,
即:dp[i][j]=sum[i][j]-min(dp[i+1][j],dp[i][j-1]),後半部分為後者所得和,前者所得和為總和減後者的和。。。。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int a[105],sum[105][105],dp[105][105]; int main(){ int n; scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d",&a[i]); dp[i][i]=a[i]; sum[i][i]=a[i]; } for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ sum[i][j]=sum[i][j-1]+a[j]; } } for(int i=n-1;i>=0;i--){ for(int j=i;j<n;j++){ dp[i][j]=sum[i][j]-min(dp[i+1][j],dp[i][j-1]); } } printf("%d %d\n",dp[0][n-1],sum[0][n-1]-dp[0][n-1]); }