UVa 10891(记忆化搜索,递推)Game of Sum
2017-07-15 08:04
218 查看
例题28 Sum游戏(Game of Sum, UVa 10891)
有一个长度为n的整数序列, 两个游戏者A和B轮流取数,A先取。
每
次玩家只能从左端或者右端取一个数, 但不能两端都取。 所有数都被取
走后游戏结束, 然后统计每个人取走的所有数之和, 作为各自的得分。
两个人采取的策略都是让自己的得分尽量高, 并且两人都足够聪明, 求A
的得分减去B的得分后的结果。
【输入格式】
输入包含多组数据。 每组数据的第一行为正整数n(1≤n≤100) , 第
二行为给定的整数序列。 输入结束标志为n=0。
【输出格式】
对于每组数据, 输出A和B都采取最优策略的情况下,A的得分减去B
的得分后的结果。
【分析】
整数的总和是一定的, 所以一个人得分越高, 另一个人的得分就越
低。 不管怎么取, 任意时刻游戏的状态都是原始序列的一段连续子序列
(即被两个玩家取剩下的序列) 。 因此, 我们想到用d(i,j) 表示原序
列的第i~j个元素组成的子序列(元素编号为1~n)
, 在双方都采取最优
策略的情况下, 先手得分的最大值(只考虑i~j这些元素) 。
状态转移时, 我们需要枚举从左边取还是从右边取以及取多少个。
这等价于枚举给对方剩下怎样的子序列: 是(k,j) (i<k≤j)
, 还是
(i, k) (i≤k<j)
。 因此:
其中, sum(i,j) 是元素i到元素j的数之和。
注意, 这里的“0”是“取
完所有数”的决策, 有了它, 方程就不需要显式的边界条件了。
两人得分之和为sum(1,n) , 因此答案是d(1,n)
-(sum(1,
n) -d(1,n)
) =2d(1,n) -sum(1,n)
。 注意, sum(i,j) 的计
算不需要循环累加, 可以预处理S[i]为前i个数之和, 则sum(i,j)
=S[j]
-S[i-1]。
下面是完整代码。 它采用了记忆化搜索的方式, 显得更加自然。
状态有O(n2) 个, 每个状态有O(n)
个转移, 所以时间复杂度为
O(n3) , 空间复杂度为O(n2)
。 对于本题的规模, 这样的时间复杂度已
经不错了, 但其实还可以进一步改进。 让我们回顾一下状态转移方程:
如果令f(i,j) =min{d(i,j)
, d(i+1,j)
, …,d(j,
120
j) } , g(i,j)
=min{d(i,j)
, d(i,j-1)
,…, d(i,i)
} , 则
状态转移方程可以写成:
f和g也可以快速递推出来:f(i,j)
=min{d(i,j)
, f(i+1,
j) } , g(i,j)
=min{d(i,j)
, g(i,j-1)
} , 因此每个f(i,j)
的计算时间都降为了O(1) 。 下面我们用递推(而非记忆化搜索) 的方
法编写。 代码如下。
有一个长度为n的整数序列, 两个游戏者A和B轮流取数,A先取。
每
次玩家只能从左端或者右端取一个数, 但不能两端都取。 所有数都被取
走后游戏结束, 然后统计每个人取走的所有数之和, 作为各自的得分。
两个人采取的策略都是让自己的得分尽量高, 并且两人都足够聪明, 求A
的得分减去B的得分后的结果。
【输入格式】
输入包含多组数据。 每组数据的第一行为正整数n(1≤n≤100) , 第
二行为给定的整数序列。 输入结束标志为n=0。
【输出格式】
对于每组数据, 输出A和B都采取最优策略的情况下,A的得分减去B
的得分后的结果。
【分析】
整数的总和是一定的, 所以一个人得分越高, 另一个人的得分就越
低。 不管怎么取, 任意时刻游戏的状态都是原始序列的一段连续子序列
(即被两个玩家取剩下的序列) 。 因此, 我们想到用d(i,j) 表示原序
列的第i~j个元素组成的子序列(元素编号为1~n)
, 在双方都采取最优
策略的情况下, 先手得分的最大值(只考虑i~j这些元素) 。
状态转移时, 我们需要枚举从左边取还是从右边取以及取多少个。
这等价于枚举给对方剩下怎样的子序列: 是(k,j) (i<k≤j)
, 还是
(i, k) (i≤k<j)
。 因此:
其中, sum(i,j) 是元素i到元素j的数之和。
注意, 这里的“0”是“取
完所有数”的决策, 有了它, 方程就不需要显式的边界条件了。
两人得分之和为sum(1,n) , 因此答案是d(1,n)
-(sum(1,
n) -d(1,n)
) =2d(1,n) -sum(1,n)
。 注意, sum(i,j) 的计
算不需要循环累加, 可以预处理S[i]为前i个数之和, 则sum(i,j)
=S[j]
-S[i-1]。
下面是完整代码。 它采用了记忆化搜索的方式, 显得更加自然。
/*状态有O(n)个,每个状态有O(n)个转移,所以时间复杂度为O(n^3),空间复杂度为O(n^2) 发现一件事:其实相互博弈就是一个相互递归的过程 可以一次取光,不可以不取 */ #include<cstdio> #include<iostream> #include<cstring> using namespace std; const int mx=105; int n,a[mx],d[mx][mx],s[mx],vis[mx][mx]; int dp(int i,int j) { if(vis[i][j]) return d[i][j]; vis[i][j]=1; int m=0;//是全部取完,此时就不需要显式的边界了 for(int k=i+1; k<=j; k++) m=min(m,dp(k,j)); for(int k=i; k<j; k++) m=min(m,dp(i,k)); return d[i][j]=s[j]-s[i-1]-m;//这个注意是i-1 } int main() { while(scanf("%d",&n)&&n) { for(int i=1; i<=n; i++) { scanf("%d",a+i); s[i]=s[i-1]+a[i]; } memset(vis,0,sizeof(vis)); printf("%d\n",2*dp(1,n)-s );//dp[1,n]-(s -dp[1,n])=2*dp(1,n)-s } return 0; }
状态有O(n2) 个, 每个状态有O(n)
个转移, 所以时间复杂度为
O(n3) , 空间复杂度为O(n2)
。 对于本题的规模, 这样的时间复杂度已
经不错了, 但其实还可以进一步改进。 让我们回顾一下状态转移方程:
如果令f(i,j) =min{d(i,j)
, d(i+1,j)
, …,d(j,
120
j) } , g(i,j)
=min{d(i,j)
, d(i,j-1)
,…, d(i,i)
} , 则
状态转移方程可以写成:
f和g也可以快速递推出来:f(i,j)
=min{d(i,j)
, f(i+1,
j) } , g(i,j)
=min{d(i,j)
, g(i,j-1)
} , 因此每个f(i,j)
的计算时间都降为了O(1) 。 下面我们用递推(而非记忆化搜索) 的方
法编写。 代码如下。
//递推解法,时间复杂度O(n^2),神奇的递推啊,推个公式得推多久啊 #include<cstdio> #include<iostream> #include<cstring> using namespace std; const int mx=105; int n,a[mx],d[mx][mx],s[mx],f[mx][mx],g[mx][mx]; int main(){ while(scanf("%d",&n)&&n) { for(int i=1;i<=n;i++) { scanf("%d",a+i); s[i]=s[i-1]+a[i]; } for(int i=1;i<=n;i++) f[i][i]=g[i][i]=d[i][i]=a[i];//边界 for(int L=1;L<n;L++) for(int i=1;i+L<=n;i++) { int j=i+L; int m=min(0,min(f[i+1][j],g[i][j-1])); d[i][j]=s[j]-s[i-1]-m; f[i][j]=min(d[i][j],f[i+1][j]); g[i][j]=min(d[i][j],g[i][j-1]); } printf("%d\n",2*d[1] -s ); } return 0; }
相关文章推荐
- 区间dp||记忆化搜索 Game of Sum UVA - 10891 or Light OJ 1031---Easy Game(区间DP)
- Uva 10891 Game of Sum - 区间DP..记忆化搜索
- sum游戏 Game of sum uva 10891 动态规划 备忘录(记忆化搜索)
- sum游戏 Game of sum uva 10891 动态规划 备忘录(记忆化搜索)
- UVA 10891 Game of Sum 记忆化搜索
- uva10891 - Game of Sum(递推,极大极小的思想)
- UVA 10891 Game of Sum 区间dp
- UVa 10891 Game of Sum
- UVA 10891 Game of Sum dp(记忆化搜索)
- 28.uva 10891 Game of Sum 记忆化dp
- UVA - 10891 Game of Sum(记忆化搜索 区间dp)
- Game of Sum UVA - 10891(动态规划)
- 28.uva 10891 Game of Sum 记忆化dp
- UVA - 10891 Game of Sum 区间DP
- Game of Sum 记忆化搜索/递推
- UVa 10891 Game of Sum - 动态规划
- UVA - 10891 Game of Sum 区间DP(博弈DP)
- UVa 10891 Game of Sum / 记忆化搜索
- 09_Sum游戏(UVa 10891 Game of Sum)
- UVA - 10891 Game of Sum 区间DP博弈