UVA 10891 - Game of Sum (博弈+区间DP+记忆化搜索)

Root  
 

10891 - Game of Sum

Time limit: 3.000 seconds
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
4
4 -10 -20 7
4
1 2 3 4
0


Sample Output
7
10


题意是可以理解为有n堆石头,A跟B两个人一次从中拿石头,每人最多可连续拿k堆,也就是不限制,A先拿。问两者都在最优的情况下,A能比B多拿几个。


首先这属于博弈问题,菜鸡对博弈了解很少,区间DP还是可以。就是枚举区间i,j,然后不断取值的操作。需要先对原数组进行处理,两层for循环,外层的i从0到n-1,内层的j从i到最后,sum数组储存从i到j的和。然后进行dfs。剩下的就是区间dp+记忆化搜索了,具体实现还是看代码吧,一目了然。


代码实现:

#include
#include
#include
#include
#include
#include
#define ll long long
#define mset(a,x) memset(a,x,sizeof(a))

using namespace std;
const double PI=acos(-1);
const int inf=0x3f3f3f3f;
const double esp=1e-6;
const int maxn=250005;
const int mod=1e9+7;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}
ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}
int dp[105][105],map[105],visit[105][105],sum[105][105],n;

int dfs(int l,int r)
{
	
	if(l>r)
	return 0;
	if(visit[l][r])                                //如果访问,返回DP[l][r] 
	return dp[l][r];
	int ans=-1e9;
	visit[l][r]=1;                                 //标记 
	
	for(int k=1;k<=r-l+1;k++)
	{
		ans=max(ans,sum[l][r]-min(dfs(l+k,r),dfs(l,r-k)));   //ans储存每次取值能得到的最大值,用sum[l][r]减去区间内最小的值就是最大值 
	}
	dp[l][r]=ans;                                           //记忆化 
	return ans;
}

int main()
{
	int i,j,k;
	while(cin>>n&&n)
	{
		mset(dp,0);
		mset(visit,0);
		for(i=0;i>map[i];
		
		for(i=0;i


你可能感兴趣的:(******DP******,******博弈******,ACM的进阶之路)