UVA 10891 Game of Sum dp(记忆化搜索)

博弈论游戏DP算法解析
本文介绍了一款两玩家博弈游戏的问题,通过动态规划解决如何让先手玩家获得尽可能多的分数。文章提供了完整的AC代码,并详细解释了状态转移方程。

Problem E

Game of Sum
Input File: 
e.in

Output: Standard Output

 

This is a two player game. Initially there are n integer numbers in an array and players A and B get chance to take them alternatively. Each player can take one or more numbers from the left or right end of the array but cannot take from both ends at a time. He can take as many consecutive numbers as he wants during his time. The game ends when all numbers are taken from the array by the players. The point of each player is calculated by the summation of the numbers, which he has taken. Each player tries to achieve more points from other. If both players play optimally and player A starts the game then how much more point can player A get than player B?

Input

The input consists of a number of cases. Each case starts with a line specifying the integer n (0 < n ≤100), the number of elements in the array. After that, n numbers are given for the game. Input is terminated by a line where n=0.

 

Output

For each test case, print a number, which represents the maximum difference that the first player obtained after playing this game optimally.

 

Sample Input                                Output for Sample Input

4

4 -10 -20 7

4

1 2 3 4

0

7

10

题意:A和B在博弈,A先开始。每次选手可以取左边连续n个或者右边连续n个,取到没有数字了,计算每个人所有取的数字之和为               每个人的分数。A和B都按最优的选择来玩,问最后A比B多多少分。

思路:dp。dp[l][r]表示区间[l,r]之间A能得到的最大分数,状态转移方程为:dp[l][r]=sum[l][r]-min(dp[l+k][r],dp[l][r-k])

           本题因为数据范围比较小,我于是用记忆化搜索来做的。写搜索总比dp写的顺……


AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define INF 10000006
using namespace std;
int f[105][105],a[105],n;
int dfs(int l,int r){
	if(l>r)return 0;
	if(f[l][r]<INF)return f[l][r];
	for(int i=1;i<=r-l+1;i++){
		int a=dfs(l,r-i);
		int b=dfs(l+i,r);
		f[l][r]=min(f[l][r],a<b?a:b);
	}
	f[l][r]=a[r]-a[l-1]-f[l][r];
	return f[l][r];
}
int main(){
	int n;
	while(scanf("%d",&n),n){
		for(int i=0;i<=n;i++)
		for(int j=0;j<=n;j++)
		f[i][j]=INF;
		f[0][0]=a[0]=0;
		for(int i=1;i<=n;i++){
			scanf("%d",a+i);
			f[i][i]=a[i];
			a[i]+=a[i-1];
		}
		printf("%d\n",2*dfs(1,n)-a[n]);
		//for(int i=1;i<=n;i++){
		//	for(int j=i;j<=n;j++){
		//		cout<<i<<' '<<j<<' '<<f[i][j]<<endl;
		//	}
		//}
	}

}



### 关于记忆化搜索的练习题 在洛谷平台上有许多涉及记忆化搜索的经典题目,这些题目可以帮助学习者更好地理解动态规划与深度优先搜索相结合的方法。以下是几个推荐的记忆化搜索练习题及其背景介绍: #### 题目一:P4170 [CQOI2007] 涂色 此题属于经典的 DP 类型问题之一,主要考察如何通过记忆化的方式优化暴力枚举的过程[^1]。 该题的核心在于利用状态压缩技术存储已经处理过的子结构,并结合 DFS 的方式逐步扩展解空间。 #### 题目二:P1464 Function 这是一个典型的递归加记忆化的入门级题目[^2]。它强调了在搜索过程中记录中间结果的重要性,从而避免不必要的重复计算。具体实现上可以通过定义一个辅助数组 `f[x][y]` 来保存已访问的状态值。 #### 题目三:UVA - 1629 Cake Slicing 这篇文章提到的一道经典例题展示了记搜的优势所在[^3]。通过对不同切割方案的结果进行缓存操作,可以显著降低时间复杂度并提高效率。 #### 题目四:滑雪 (P1434) 作为一道非常受欢迎的记忆化搜索练习题,“滑雪”模拟了一个二维网格上的最长下降路径求解过程[^5]。给定一张地图表示各个位置的高度分布情况后,我们需要找到从任意起点出发能够达到的最大步数长度。 ```python from functools import lru_cache @lru_cache(None) def dfs(x, y): res = 1 directions = [(0,-1),(-1,0),(0,+1),(+1,0)] for dx, dy in directions: nx, ny = x + dx, y + dy if 0<=nx<R and 0<=ny<C and grid[nx][ny]<grid[x][y]: res = max(res, dfs(nx, ny)+1 ) return res R,C=map(int,input().split()) grid=[list(map(int,input().strip().split()))for _ in range(R)] ans=0 for i in range(R): for j in range(C): ans=max(ans ,dfs(i,j)) print(ans) ``` 上述代码片段实现了基于 Python 的解决方案,其中运用装饰器 @lru_cache 实现自动化的函数调用结果缓存功能。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值