HDU4778 Gems Fight!

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4778

题目大意:有B个包裹,里面有各种颜色的GEM,共有G个颜色。Alice和Bob轮流挑选包裹放到一个地方,如果挑选出来的同种颜色的GEM超过S个,当前回合者可以得分,每超过S个得一分。如果在回合内得分了,可以额外进行一个回合。问Alice的得分减去Bob的得分最大是多少。

分析:很明显的极大极小。基本上可以说和POJ1085一样的,记忆化搜索 + 状态压缩

代码:

#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cassert>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <list>
#include <stdexcept>
#include <functional>
#include <utility>
#include <ctime>
using namespace std;

/** some operate*/
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,l,h) for(int i=(l);i<=(h);++i)
#define DWN(i,h,l) for(int i=(h);i>=(l);--i)
#define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
#define CLR(arr) memset(arr,0,sizeof(arr))

/** some const*/
#define N 300010
#define PI acos(-1.0)
#define oo 1000000000
#define loo 1000000000000000000LL
/** some alias*/
typedef long long ll;
typedef double db;

int dx[]={0,-1,0,1, -1,-1,1,1};
int dy[]={1,0,-1,0, -1,1,-1,1};
/** Global variables*/

struct node
{
    int c[10];
}Bag[30];

int b,g,s,now[10],sg[1<<22];

int judge(int k)
{
    int temp,total = 0;
    REP(i,g+1)
    {
        temp = now[i] + Bag[k].c[i];
        if(temp >= s)
        total += temp / s;
    }
    return total;
}

int dfs(int dp)
{
    if(sg[dp] != -oo)
        return sg[dp];
    int tep[10],ans = -oo;
    REP(i,g+1)
    tep[i] = now[i];
    REP(i,b)
    {
        int k = 1 << i;
        if(!(dp & k))
        {
            int total = judge(i);
            REP(j,g+1)
            now[j] = (now[j] + Bag[i].c[j] ) % s;
            if(total > 0)
                ans = max(ans,total + dfs(dp|k));
            else
                ans = max(ans,total - dfs(dp|k));
            REP(j,g+1)
            now[j] = tep[j];
        }
    }
    return sg[dp] = ans;
}

void init()
{
    int k = 1 << b;
    REP(i,k)
    sg[i] = -oo;
    sg[k-1] = 0;
}

int main()
{
    //freopen("a","r",stdin);
    //freopen("wa","w",stdout);
    int n,m,t,cs=0;
    while(~scanf("%d%d%d",&g,&b,&s))
    {
        if(!b && !g && !s)
            break;
        init();
        CLR(now);
        CLR(Bag);
        REP(i,b)
        {
            scanf("%d",&n);
            while(n--)
            {
                scanf("%d",&m);
                Bag[i].c[m]++;
            }
        }
        printf("%d\n",dfs(0));
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值