题目描述 Description
小毛终于到达宝藏点,他意外地发现有一个外星人(名叫Pluto)。宝藏是一些太空黄金,有n堆排成一行,每堆中有xi颗黄金。小毛和Pluto决定轮流从中取出黄金,规则是每次只能从最左边或最右边取出一堆黄金,直到所有黄金被取出。小毛先取,两人都以最优策略进行选取,求两人的最后所得。
输入描述 Input Description
第一行是正数n(≤500);第二行为n个正整数xi(≤300),表示每堆黄金的个数。
输出描述 Output Description
仅两个整数,分别表示小毛和Pluto的得分,以空格隔开。
样例输入 Sample Input
6
4 7 2 9 5 2
样例输出 Sample Output
18 11
正解:DP
解题报告:
看到这是博弈的时候有一点慌。。。好吧其实只用了思想。
显然DP可行,f[i][j]表示从i到j的区间的最优策略,最后f[1][n]即先手得分,总和减掉这个最优值即为后手得分。
转移也比较好想,只是有一个地方比较神。显然由从左端选了一堆或者从右端选了一堆转移过来,而我们取得是较小的那个值,因为我们需要后手决策尽可能贡献小。
细节看代码吧。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 501; 21 int n; 22 int a[MAXN],sum[MAXN]; 23 int f[MAXN][MAXN];//f[i][j]表示从i到j的最优策略得分 24 25 inline int getint() 26 { 27 int w=0,q=0; 28 char c=getchar(); 29 while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar(); 30 if (c==‘-‘) q=1, c=getchar(); 31 while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar(); 32 return q ? -w : w; 33 } 34 35 inline void work(){ 36 n=getint(); 37 for(int i=1;i<=n;i++) a[i]=getint(),f[i][i]=a[i],sum[i]=sum[i-1]+a[i]; 38 for(int len=1;len<=n-1;len++) 39 for(int i=1;i<=n-len;i++) 40 f[i][i+len]=sum[i+len]-sum[i-1]-min(f[i+1][i+len],f[i][i+len-1]);//减去部分是后手的决策最小值 41 printf("%d %d",f[1][n],sum[n]-f[1][n]);//总和减去先手最优决策即为后手得分 42 } 43 44 int main() 45 { 46 work(); 47 return 0; 48 }
时间: 2024-10-18 00:38:45