【USACO题库】3.3.5 A Game游戏

题目大意:

求在一个序列里(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题库】3.3.5 A Game游戏)