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,经典**/ /******************************************************************************************** 最大的难关就是要想出如何表示状态,正确划分状态区间,然后状态转移方程就能很容易想出。 我们用dp[i][j]代表在本题的规则下,从数列{a[i]……a[j]}中先手能够取得的最大值。 状态转移方程dp[i][j]=sum{a[i]……a[j]}-min(dp[i+1][j],dp[i][j-1]). 解释:假设本轮A先手,取的数列是{a[i]……a[j]},他只有两种选择:a[i]和a[j],那下一轮 他的对手就会成为先手,取得数列也是两种选择。而对应的状态是dp[i+1][j]和 dp[i][j-1].对于本 轮的先手A来说,他想要获胜必须保证他的对手B每次取的都是B所能取得的最小值,即他的对手取的 应该是dp[i+1][j]和dp[i][j-1]的最小值。 细节:我们注意到了dp[i][j]与dp[i+1][j]和dp[i][j-1]有关,因此,当求dp[i][j]时,必须使 dp[i+1][j]和dp[i][j-1]都存在,因此i循环应该从n减到1,j应该从1加到n. ********************************************************************************************/ #include <iostream> #include <cstdio> #include <cstring> #define MAX 220 using namespace std; int min(int a,int b) { return a<b?a:b; } int main() { freopen("game1.in","r",stdin); freopen("game1.out","w",stdout); int dp[MAX][MAX]= {0}; int sum[MAX]= {0}; int a[MAX]= {0}; int j,k,i,n; scanf("%d",&n); for(i=1; i<=n; i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; dp[i][i]=a[i]; } for(j=n-1; j>=1; j--) for(k=j+1; k<=n; k++) dp[j][k]=(sum[k]-sum[j-1])-min(dp[j+1][k],dp[j][k-1]); cout<<dp[1][n]<<" "<<sum[n]-dp[1][n]<<endl; return 0; }