首页 > 代码库 > HDU 4778 Gems Fight! (状态压缩 + 博弈)
HDU 4778 Gems Fight! (状态压缩 + 博弈)
OJ题目 : click here ~~
题目分析:G种颜色的宝石(Gems),放在B个包里,每个包里同种宝石的个数不定哦。A,B轮流取一个包,宝石放在cooker上,同种颜色的宝石达到S个时,就可以融合成一个魔法石,如果2*S个当然就可以融合成两个魔法石啦。某人在某轮获得了魔法石,可以接着再玩一轮,直到没有获得魔法石。A先开始。问A比B 最多能多多少个魔法石。A,B都采用最优策略。
B的值最大为21,可以二进制表示每一个状态。
设dp[ i ] 表示状态 i 时,A比B最多多dp [ i ] 个魔法石。 详见代码注释。
AC_CODE
int G , B , S ; int Back[25][11] ; int dp[1<<21] ;//状态为i时,先手比后手多的魔法石的个数。i的二进制表示中1标示未选过,0标示已经选过。 int remain[11]; int have[11]; int main(){ while(scanf("%d%d%d",&G , &B , &S) != EOF){ if(G == 0 && B == 0 && S == 0) break; memset(Back , 0 , sizeof(Back)); int i , j , k , x; for(i = 0;i < B;i++){ scanf("%d",&k); while(k--){ scanf("%d",&x); Back[i][x]++; } } dp[0] = 0; for(i = 1;i < (1<<B);i++){//计算到i状态,cooker上各种颜色宝石的个数。 memset(remain , 0 , sizeof(remain)); dp[i] = -(1<<30); for(j = 0;j < B;j++){ if((i & (1<<j)) == 0){ for(k = 1;k <= G;k++){ remain[k] += Back[j][k]; while(remain[k] >= S) remain[k] -= S; } } } for(j = 1;j <= G;j++) have[j] = remain[j]; for(j = 0;j < B;j++){//计算状态i下,选择包j if(i & (1<<j)){//计算选择包j时,能获得多少魔法石 int bonus = 0; for(k = 1;k <= G;k++){ int a = have[k] + Back[j][k]; while(a >= S){ bonus++; a -= S; } } if(bonus > 0) dp[i] = max(dp[i] , bonus + dp[i^(1<<j)]);//如果能获得魔法,下轮依然是本人 else dp[i] = max(dp[i] , - dp[i^(1<<j)]);//没有获得魔法石,下轮是对手 } } } cout << dp[(1<<B) - 1] << endl; } return 0 ; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。