題目描述
題目意思是給你一個序列, 兩個玩家, 每個玩家可以從序列的開頭或者末尾取一個數,問兩個玩家都採取最優策略,第一個玩家得分最多是多少?
樣例輸入&輸出
sample input
6
4 7 2 9 5 2
sample output
18 11
分析&反思
明顯是動態規劃的題目,想到了以長度爲階段,但dp數組的意義沒有把握好,應該是這一序列先手能取到的最大數字和。
題解裏利用了sum數組,這樣sum數組存儲所有數字和,dp數組存儲先手的最大數字和,相減得到後手的最大數字和。
狀態轉移方程:dp[ i ] [ j ] = sum[ i ] [ j ] “-減” min { dp[ i+1 ] [ j ] , dp[ i ] [ j-1 ] }。
(即 (選 i) 或 (選 j) 後,此時後手成爲 (i+1 到 j) 或 (i 到 j-1) 的先手, 減去後便是 (i或j) 加 (i+1到j 或 i到j-1 的後手) 之和 )
代碼
#include<cstdio>
#include<iostream>
using namespace std;
int a[103], sum[103][103], f[103][103], n;
int main() {
freopen("game1.in", "r", stdin);
freopen("game1.out", "w", stdout);
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
f[i][i] = sum[i][i] = a[i];
}
for(int k = 2; k <= n; k++)
for(int i = 1; i <= n-k+1; i++) {
sum[i][i+k-1] = sum[i][i+k-2]+a[i+k-1];
}
for(int k = 2; k <= n; k++)
for(int i = 1; i <= n-k+1; i++) {
f[i][i+k-1] = sum[i][i+k-1] - min(f[i+1][i+k-1], f[i][i+k-2]);
}
printf("%d %d\n", f[1][n], sum[1][n]-f[1][n]);
return 0;
}