• hdu4778:状压dp+博弈


    题目大意:

    有g种不同颜色的小球,b个袋子,每个袋子里面有若干个每种小球

    两人轮流取袋子,当袋子里面的同色小球有s个时,会合并成一个魔法球,并被此次取袋子的人获得

    成功获得魔法球的人可以再次取

    求二者都进行最优策略之后两人所得魔法球个数差

    分析:

    博弈,数据很小,自然想到了可以搜索所有状态

    然后从每一步的子状态中找到对当前人(这一步的先手)最有利的状态即可

    直接搜索还是会超时的,于是想到用状态压缩一下,做记忆化搜索

    然后其实就是一个状压dp了

    通过某个状态对于先手的最优子状态进行转移。。

    代码如下

    #include <iostream>
    #include <stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<string>
    #include<ctype.h>
    using namespace std;
    #define MAXN 10000
    typedef struct Node
    {
        int a,b;
    }node;
    node dp[2097152];
    bool vi[2097152];
    int num[25][25];
    int p[8];
    int g,b,s,k,m,x;
    void dfs(int state,int turn)
    {
        if(state==(1<<b)-1)
        {
            dp[state].a=0;
            dp[state].b=0;
            return ;
        }
        if(vi[state])
        {
            return ;
        }
        int ok;
        node t;
        node ans;
        ans.a=-1000000;
        ans.b=0;
        int pp[8];
        memcpy(pp,p,sizeof(pp));
        for(int i=0;i<b;i++)
        {
            t.a=0;
            t.b=0;
            ok=0;
            if(state&(1<<i))
              continue;
            int st=state|(1<<i); //状态
            for(int j=0;j<g;j++)
            {
                p[j]+=num[i][j];
                ok+=p[j]/s;
                p[j]%=s;
            }
            int tur=ok?turn:!turn;//是否交换选手
            dfs(st,tur);
            memcpy(p,pp,sizeof(pp));
            t.a+=ok;
            if(tur==turn)   //子状态的先手所要转移到的状态相同
            {
                t.a+=dp[st].a;
                t.b+=dp[st].b;
            }
            else            //选手交换了
            {
                t.b+=dp[st].a;
                t.a+=dp[st].b;
            }
            if(t.a-t.b>ans.a-ans.b)
            {
                ans=t;
            }
        }
        vi[state]=1;
        dp[state]=ans;
        return ;
    }
    int main()
    {
        while(scanf("%d%d%d",&g,&b,&s),g+b+s)
        {
            memset(num,0,sizeof(num));
            for(int i=0;i<b;i++)
            {
                scanf("%d",&k);
                while(k--)
                {
                    scanf("%d",&x);
                    num[i][x-1]++;
                }
            }
            memset(p,0,sizeof(p));
            memset(vi,0,sizeof(vi));
            dfs(0,0);
            printf("%d
    ",dp[0].a-dp[0].b);
        }
        return 0;
    }
  • 相关阅读:
    .NET设计模式系列文章
    [转]给年轻工程师的十大忠告
    [你必须知道的.NET]第二十回:学习方法论
    写给开发者看的关系型数据库设计
    AjaxPro使用说明
    Spring.Net入门篇(一) [转]
    [从设计到架构] 必须知道的设计模式
    4月1日SharePoint Designer将开始免费
    12月累计更新的一个导出导入网站的问题在2月累计更新中修复了
    修复错误1093 “Unable to get the private bytes memory limit for the W3WP process”
  • 原文地址:https://www.cnblogs.com/oneshot/p/4025179.html
Copyright © 2020-2023  润新知