题目大意:
求在一个序列里(1<n<=100),两个人从序列的两端取数,第一个人最优策略的最优得分是多少(需保证第二个人也得是最优策略)
样例输入:
6
4 7 2 9 5 2
样例输出:
18 11
解释:
两人依次选的是:2,4,7,5,9,2
第一个人=2+7+9=18
第二个人=4+5+2=11
这道题实质上是一道动态规划类题目,因为两人所选的策略都是最优策略,并不是一个贪心策略。所以,我们可以想到把一个序列来分段,也就是当前两人分别在取的序列的开头和结尾来做一个分段——也就是设f[i,j]表示i~j这个区间里先手可以获得的最优值。
状态转移方程:
f[i,j]=sum[i,j]-min(f[i-1,j],f[i,j-1]);
sum[i,j]表示i~j这个区间里的总和;
f[i-1,j]表示先手取左边而后手可获得的最优值;
f[i,j-1]表示先手取右边而后手可获得的最优值;
f[i-1,j],f[i,j-1]两者之间的最小值就是当前先手应该取的位置。
边界:
f[i,i]=a[i](1<=i<=n)
代码:
var
f,sum:array[0..100,0..100]of longint;
n,i,j:longint;
a:array[1..100]of longint;
function min(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y);
end;
procedure init;
begin
fillchar(sum,sizeof(sum),0);
for i:=1 to n-1 do
for j:=i to n do
sum[i,j]:=sum[i,j-1]+a[j];
for i:=1 to n do
f[i,i]:=a[i];
end;
procedure work;
begin
for i:=n-1 downto 1 do
for j:=i+1 to n do
f[i,j]:=sum[i,j]-min(f[i,j-1],f[i+1,j]);
end;
begin
readln(n);
for i:=1 to n do
read(a[i]);
init;
work;
writeln(f[1,n],' ',sum[1,n]-f[1,n]);
end.
本文介绍了USACO竞赛中的一道题目,涉及到两人在序列两端取数的游戏,要求找出第一个人最优策略下的最大得分,保证对方也采用最优策略。通过动态规划的方法,设立状态转移方程解决此问题。样例输入和输出展示了具体的操作过程。
450

被折叠的 条评论
为什么被折叠?



