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;
}


            
举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG
原文地址:https://www.cnblogs.com/AbandonZHANG/p/2620838.html