hdu 4778 Gems Fight! 2013 Asia Hangzhou Regional Contest

来源:互联网 发布:知豆电动车好不好 编辑:程序博客网 时间:2024/05/16 12:22

这一题特别像大白书Ch1的 ex.28 Sum游戏,臣妾对着这个example+看了一堆题解终于把这道博弈DP想清楚了%>_<%
首先要注意这一题里面总的score是不变的,因为bag都放在同一个cooker里,magic stone要么给A要么给B
用二进制数表示当前状态,1001表示A or B有第一个和第四个bag可以选,第二个和第三个bag之前已经选过了(即不可选)所以对应的score[1001]应该计算把第二个和第三个bag放到cooker可以得到的score,我开始把这个弄反了==算成了第一个和第四个的score==
dp[state]表示当前状态(有哪些bag可选,有哪些bag已经选过了)开始博弈,到最后先手得分的最大值。
状态转移时,假设state对应的是A是先手,如果state&(1<<i)!=0,则说明bag i可选,下一个状态就是newstate=state^(1<<i),newstate其实就是将state里面的i位从1变到0,表示已经选过了bag i。
改变的分数就是val=score[newstate]-score[state]
如果val>0,那么下一步还是A,所以dp[state]=max(dp[state],val+dp[newstate])
如果选bag i无法使得A加分,那么下一步就换成B是先手,所以dp[newstate]就表示B是先手,选到最后,B得分最大值,因为总分数一定的,所以A的分数=state状态下对应的总分数-dp[下一个回合B先出手] 
state状态下对应的总分数=score[0]-score[state],假设state=1001,那么现在还可以把bag 1 and bag 4放进去,而score[1001]表示把bag 2 和bag 3 放进cooker的得分,所以要用total score相减
因为一直取max,就可以保证是最优的。
这里面状态转移不会转移到非法的状态,所以记忆化搜索里面也木有非法状态的特判。

最后的分数=dp[(1<<b)-1]-(score[0]-dp[(1<<b)-1]),score[0]表示total score

DP过程中先手后手对应的是A还是B是会变的==

#include<iostream>#include<stdio.h>#include<cstdio>#include<stdlib.h>#include<vector>#include<string>#include<cstring>#include<cmath>#include<algorithm>#include<stack>#include<queue>#include <ctype.h>#include<map>#include<time.h>using namespace std;//hdu 4778const int maxn=1<<21;int b;int g;int n;int s;int c[22][12];int score[maxn];int sum[20];int dp[maxn];int vis[maxn];void caltotal()//计算cooker中每个状态的score,=0表示已经选过了放进了cooker{    for(int m=0;m<(1<<b);m++)    {        memset(sum,0,sizeof(sum));        for(int i=0;i<b;i++)        {            if((m&(1<<i))==0)            {                for(int j=1;j<=g;j++)                {                    sum[j]+=c[i][j];                }            }        }        for(int i=1;i<=g;i++)        {            score[m]+=sum[i]/s;        }    }}int dfs(int state){    if(vis[state])    {        return dp[state];    }    vis[state]=1;    int ret=0;    for(int i=0;i<b;i++)    {        if(state&(1<<i))//=1表示当前状态已经存在bag i,所以i可选。向选过bag i的状态转移(所以newstate的i位是0)        {            int newstate=state^(1<<i);            int val=score[newstate]-score[state];            if(val>0)            {                ret=max(ret,val+dfs(newstate));            }            else            {                ret=max(ret,(score[0]-score[state])-dfs(newstate));                //所有bag都放到cooker中的score-当前状态还有某些包可选对应的score(只放了一部分bag到cooker里的score)=s当前状态的总分数            }        }    }    return dp[state]=ret;//一定要赋值才能实现记忆化搜索!}int main(){    freopen("input.txt","r",stdin);    //freopen("data.txt","r",stdin);    //freopen("out1.txt","w",stdout);    while(true)    //while(scanf("%d %d %d",&g,&b,&s),g|b|s)    {        scanf("%d %d %d",&g,&b,&s);        if(!b&&!g&&!s) break;        memset(score,0,sizeof(score));        memset(c,0,sizeof(c));        memset(dp,0,sizeof(dp));        memset(vis,0,sizeof(vis));        for(int i=0;i<b;i++)        {            scanf("%d",&n);            for(int j=0;j<n;j++)            {                int color=0;                scanf("%d",&color);                c[i][color]++;            }        }        caltotal();        int ans=dfs((1<<b)-1)*2-score[0];//0表示已经选过放在cooker中了,所以score[0]是总的分数        //dp[11...11]-(total score-dp[11...11])        printf("%d\n",ans);    }     return 0;}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 转了户口社保怎么办 政府咨询电话打不通怎么办 公务员准考证丢了怎么办 行测老打40多分怎么办 网上没有报名的怎么办? 上大学转户口怎么办 梅菜扣肉勾芡怎么办 有个精神病妈妈怎么办 妈得了精神病该怎么办 思维不正常的人怎么办 妈妈是个精神病怎么办 我老婆有精神病怎么办 在郑州怎么办完税证明 中专没考上大专怎么办 考研两次没考上怎么办 2018造价员取消后怎么办 造价员取消了投标怎么办 造价员考试取消后怎么办 只拿到结业证怎么办 本科只有结业证怎么办 健身后肌肉水肿怎么办 大腿面肌肉疼怎么办 跑步后大腿酸疼怎么办? 运动后大腿胀痛怎么办 尔雅课程没看完怎么办 国家课程校本化怎么办 上海买房限购怎么办 投资公司要求回购股份怎么办 超过应届生落户年龄怎么办 造价员章到期了怎么办 造价员继续教育过期了怎么办 sd卡存储不够怎么办? 进项税大于销项税怎么办 公司扣员工奖金怎么办 墙面大面积有霉怎么办 电脑总是断网怎么办 造价师资格证书丢了怎么办 行测做题速度太慢怎么办 普通话准考证丢了怎么办 信用卡还款逾期了怎么办 淮北建洗煤厂需要怎么办