题意: 小 ho 和小 hi 在玩游戏,给定一个数字串,每人每次从该串的开头或结尾选取一个数,直到选完为止,最后选取数字之和较大的那个人获胜。其中小 ho 先手。求小 ho 能获得的最大分数。
思路: 由样例可以看出,每次选取首尾中较大的数的这个贪心策略是错误的。
设
f[i][i]
表示对于
A[i,...,j]
数字串的先手能够获得的最大分数。
当 i==j 时,则
f[i][i]=A[i]
;
当 i < j 时,则先手可能选择
A[i]
或者
A[j]
。如果先手选择
A[i]
,则后手得到的数字串是
A[i+1,...,j]
,对应的后手能从该数字串中得到
f[i+1][j]
的最大分数。则后手肯定会按照能够获得最大分数的决策进行下一步选择,则此时先手能够获得的最大分数就是
∑k=i−>jA[k]−f[i+1][j]
。如果先手选择
A[j]
同理。
所以最终
f[i][j]=max(∑k=i−>jA[k]−f[i+1][j],∑k=i−>jA[k]−f[i][j−1])
。
代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int N;
int A[1010];
int f[1010][1010];
int s[1010][1010];
int main()
{
//freopen("in.txt", "r", stdin);
while(scanf("%d", &N) == 1){
for(int i=0; i<N; i++){
scanf("%d", &A[i]);
}
for(int i=0; i<N; i++){
for(int j=i; j<N; j++){
if(i == j) s[i][j] = A[i];
else{
s[i][j] = A[j]+s[i][j-1];
}
}
}
for(int i=0; i<N; i++){
f[i][i] = A[i];
}
for(int len=2; len<=N; len++){
for(int i=0; i+len-1<N; i++){
int j = i+len-1;
f[i][j] = s[i][j]-min(f[i+1][j], f[i][j-1]);
}
}
printf("%d\n", f[0][N-1]);
}
return 0;
}