USACO 3.4 A Game

http://ace.delos.com/usacoprob2?a=5yeP9Cco705&S=game1

题意:有一个两个人的游戏,游戏的规则是这样的:给你一个有N个数的数列,每次有一个选择这样数列的一端将该数删除,所得的分数就是该是的值,游戏从P1开始,问假设两个人都采用最优策略,最后两个人的得分是多少。

思路:博弈问题,可以用动态规划解决。状态为:dp[i][j][0] : 表示将[ i , j ]区间内的数删除,从P2开始P2最多能得的分数,dp[i][j][1]:表示将[ i , j ]区间内的数删除,游戏从P1开始,P2最多能得的分数。

状态转移方程为: dp[ i ] [ j ] [ 0 ] = MAX( dp[ i+1 ] [ j ] [ 1 ] + num [ i ]  , dp[ i ] [ j -1 ] [ 1 ] + num [ j ] );

dp[ i ] [ j ] [ 1 ]  = MIN( dp[ i ] [ j ] [ 0]  , dp[ i ] [ j ] [ 0 ] ) ;  //这里是MIN是因为两者都采取最优的策略。

代码:

/*
ID : chris
LANG :C++
TASK : game1
*/
#include<stdio.h>
#include<string.h>
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(b):(a) 
int dp[210][210][2] ;
int N ,sum;
int num[210] ;
void DP(){
	memset(dp , 0 ,sizeof(dp) );
	for(int i=1;i<=N;i++){
		dp[i][i][0] = num[i] ;
		dp[i][i][1] = 0 ;
	}
	
	for(int len=2;len<=N;len++){
		for(int i=1;i+len<=N+1;i++){
			int j = i + len - 1;
			dp[i][j][0] = MAX( dp[i+1][j][1] + num[i] , dp[i][j-1][1] + num[j] );
			dp[i][j][1] = MIN( dp[i+1][j][0] , dp[i][j-1][0] );
		}
	}
	printf("%d %d\n",sum-dp[1][N][1],dp[1][N][1]);
}
int main(){
	freopen("game1.in","r",stdin);
	freopen("game1.out","w",stdout);
	while(scanf("%d",&N) == 1){
		sum = 0 ;
		for(int i=1;i<=N;i++){
			scanf("%d",&num[i]);
			sum += num[i] ;
		}
		DP();
	}	

	return 0; 
}


你可能感兴趣的:(USACO 3.4 A Game)