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)
只有一行,用空格分隔的两个整数: 依次为玩家一和玩家二最终的得分。
6
4 7 2 9 5 2
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; }