USACO 3.3.5 A Game 游戏
博弈问题,可以使用动态规划求解。 状态定义:用F[i][j]表示第一个玩家先取时,在第i到第j的子序列中能拿到的最高分;用S[i][j]表示第i到第j的子序列中所有数字的和;用num[i]表示第1到第n的序列中第i个数。
边界条件:F[i][i]=num[i]
状态转移方程: F[i][j]=max{num[i]+S[i+1][j]-F[i+1][j],num[j]+S[i][j-1]-F[i][j-1]}
结果 p1=F[1][n]; p2=S[1][n]-F[1][n];
解析: num[i]+S[i+1][j]-F[i+1][j]表示的是,p1拿第i到第j最左边的数,然后轮到p2在第i+1到第j的序列中先取,会剩下S[i+1][j]-F[i+1][j],这些归p1。
USER: CmYkRgB CmYkRgB [cmykrgb1] TASK: game1 LANG: C++
Compiling... Compile: OK
Executing... Test 1: TEST OK [0.000 secs, 3000 KB] Test 2: TEST OK [0.011 secs, 3004 KB] Test 3: TEST OK [0.000 secs, 3000 KB] Test 4: TEST OK [0.000 secs, 3000 KB] Test 5: TEST OK [0.000 secs, 3000 KB] Test 6: TEST OK [0.022 secs, 3000 KB] Test 7: TEST OK [0.000 secs, 3000 KB] Test 8: TEST OK [0.011 secs, 3000 KB] Test 9: TEST OK [0.011 secs, 3004 KB] Test 10: TEST OK [0.000 secs, 3004 KB] Test 11: TEST OK [0.011 secs, 3004 KB] Test 12: TEST OK [0.000 secs, 3000 KB] Test 13: TEST OK [0.011 secs, 3000 KB] Test 14: TEST OK [0.000 secs, 3000 KB] Test 15: TEST OK [0.000 secs, 3004 KB] Test 16: TEST OK [0.011 secs, 3004 KB]
All tests OK.
YOUR PROGRAM ('game1') WORKED FIRST TIME! That's fantastic -- and a rare thing. Please accept these special automated congratulations.
/*
ID: cmykrgb1
PROG: game1
LANG: C++
*/
#include <iostream>
#include <fstream>
#define MAXN 201
using namespace std;
ifstream fi("game1.in");
ofstream fo("game1.out");
long n,ori,ans,ans2;
long F[MAXN][MAXN],num[MAXN];
inline long max(long a,long b)
{
return a>b?a:b;
}
long get_S(long a,long b)
{
long p=0;
for (long i=a;i<=b;i++)
p+=num[i];
return p;
}
long get_F(long i,long j)
{
if (F[i+1][j]==ori)
F[i+1][j]=get_F(i+1,j);
if (F[i][j-1]==ori)
F[i][j-1]=get_F(i,j-1);
return max(num[i]+get_S(i+1,j)-F[i+1][j],num[j]+get_S(i,j-1)-F[i][j-1]);
}
void init()
{
long i;
fi >> n;
memset(F,0xF,sizeof(F));
ori=F[0][0];
for (i=1;i<=n;i++)
{
fi >> num[i];
F[i][i]=num[i];
}
}
void print()
{
fo << ans << ' ' << ans2 << endl;
fi.close();
fo.close();
}
int main()
{
init();
ans=get_F(1,n);
ans2=get_S(1,n)-ans;
print();
return 0;
}