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;
}