Codeforces Round #222 (Div. 1) C. Captains Mode 对弈+dp
题目链接:
http://codeforces.com/contest/378/problem/E
题意:
dota选英雄,现在有n个英雄,m个回合,两支队伍:
每一回合两个选择:
b 1,队伍一ban掉一个英雄,或是跳过这个回合
p 1,队伍1选一个英雄
现在每个队伍都是最优决策,问最后队伍一的英雄实力和-队伍二的英雄实力和。
题解:
状压dp,决策要倒过来做,也就是dp出后面回合的决策的基础上设计出对自己当前回合对自己最有利的决策。、
注意:只有top m的英雄有可能被选,其他的都不可能被选中。
dp[x]表示目前回合两支队伍的实力差。(其中每一位bit代表一个英雄,1说明英雄被ban或被p了,0表示该英雄还没有被选或被ban。
代码;
#include<iostream> #include<utility> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<algorithm> using namespace std; typedef long long LL; const int maxn=1<<22; const int INF=0x3f3f3f3f; int dp[maxn],op[25],val[111]; int n,m,team[25]; inline int cnt_bit(int x){ return x==0?0:(x&1)+cnt_bit(x>>1); } bool cmp(int a,int b){ return a>b; } int main(){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",val+i); sort(val,val+n,cmp); scanf("%d",&m); char s[11]; for(int i=m;i>=1;i--){ scanf("%s%d",s,&team[i]); op[i]=(s[0]=='p'); } dp[0]=0; for(int i=1;i<(1<<m);i++){ int cur=cnt_bit(i); if(team[cur]==1){ dp[i]=-INF; for(int j=0;j<m;j++){ if(i&(1<<j)){ dp[i]=max(dp[i],dp[i^(1<<j)]+op[cur]*val[j]); } } }else{ dp[i]=INF; for(int j=0;j<m;j++){ if(i&(1<<j)){ dp[i]=min(dp[i],dp[i^(1<<j)]-op[cur]*val[j]); } } } } printf("%d\n",dp[(1<<m)-1]); return 0; }