USACO / A Game (经典区间DP)

A Game游戏

IOI'96 - Day 1

 

有如下一个双人游戏:N(2 <= N <= 100)个正整数的序列放在一个游戏平台上,游戏由玩家1开始,两人轮流从序列的两端取数,取数后该数字被去掉并累加到本玩家的得分中,当数取尽时,游戏结束。以最终得分多者为胜

描述

编一个执行最优策略的程序,最优策略就是使玩家在与最好的对手对弈时,能得到的在当前情况下最大的可能的总分的策略。你的程序要始终为第二位玩家执行最优策略。

格式

PROGRAM NAME: game1

INPUT FORMAT:

(file game1.in)

第一行: 正整数N, 表示序列中正整数的个数。

第二行至末尾: 用空格分隔的N个正整数(大小为1-200)。

OUTPUT FORMAT:

(file game1.out)

只有一行,用空格分隔的两个整数: 依次为玩家一和玩家二最终的得分。

SAMPLE INPUT

6 

4 7 2 9 5 2

SAMPLE OUTPUT

18 11


分析:
  简单又比较经典的区间DP,每个状态无非就是这个人从左边拿还是从右边拿嘛,然后我们看怎么表达出状态转移方程。
  子问题:假设当前状态a1,a2,a3,a4,a5,如果第一个人选最左边的,则问题转化为四个数a2,a3,a4,a5,然后第二个人先选,由于题目说第二个人方案也最优,所以选的也是最优方案;先选右边同理。
  转移方程:设f[i][j]表示选[i,j]区间的数,先选的那个人的最优方案。则:
        
      f[i][j]=Max{ sum[i+1][j]-f[i+1][j]+a[i](先选左边),sum[i][j-1]-f[i][j-1]+a[j](先选右边) }

        因为选了一个后转化成的子问题,第二个人是先选,所以第一个人只能拿到子问题的后选的人的解,即sum[i][j]-f[i][j]。


USER: Zhipeng ZHANG [138_3531]

TASK: game1

LANG: C++



Compiling...

Compile: OK



Executing...

   Test 1: TEST OK [0.000 secs, 3212 KB]

   Test 2: TEST OK [0.000 secs, 3212 KB]

   Test 3: TEST OK [0.000 secs, 3212 KB]

   Test 4: TEST OK [0.000 secs, 3212 KB]

   Test 5: TEST OK [0.000 secs, 3212 KB]

   Test 6: TEST OK [0.000 secs, 3212 KB]

   Test 7: TEST OK [0.000 secs, 3212 KB]

   Test 8: TEST OK [0.000 secs, 3212 KB]

   Test 9: TEST OK [0.000 secs, 3212 KB]

   Test 10: TEST OK [0.000 secs, 3212 KB]

   Test 11: TEST OK [0.000 secs, 3212 KB]

   Test 12: TEST OK [0.000 secs, 3212 KB]

   Test 13: TEST OK [0.000 secs, 3212 KB]

   Test 14: TEST OK [0.000 secs, 3212 KB]

   Test 15: TEST OK [0.000 secs, 3212 KB]

   Test 16: TEST OK [0.000 secs, 3212 KB]



All tests OK.

Your program ('game1') produced all correct answers! This is your submission #2 for this problem. Congratulations!

 
/*

ID:138_3531

LANG:C++

TASK:game1

*/



#include<fstream>

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

#include<fstream>

#include<queue>

#include<climits>

#include<vector>

#include<map>

#include<cmath>



using namespace std;



int Max(int x,int y)

{

    return x>y?x:y;

}



int main()

{

    freopen("game1.in","r",stdin);

    freopen("game1.out","w",stdout);



    int a[100];

    int f[100][100];       //

    int sum[100][100];

    memset(sum,0,sizeof(sum));

    memset(f,0,sizeof(f));



    int n;

    cin>>n;





    for (int i=0;i<n;i++)

        cin>>a[i];



    for (int i=0;i<n;i++)

        for (int j=i;j<n;j++)

            for (int k=i;k<=j;k++)

                sum[i][j]+=a[k];

    for (int i=n-1;i>=0;i--)

        for (int j=i;j<n;j++)

        if (i==j)

            f[i][j]=a[i];

        else

            f[i][j]=Max(sum[i+1][j]-f[i+1][j]+a[i],sum[i][j-1]-f[i][j-1]+a[j]);



    cout<<f[0][n-1]<<" "<<sum[0][n-1]-f[0][n-1]<<endl;



    return 0;

}
 
  

 

            

你可能感兴趣的:(USACO)