2013 ACMICPC 杭州现场赛 I题

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define Maxn 100
using namespace std;
int dp[1<<21],num[Maxn],bag[Maxn][Maxn],g,b,s,now[22];
bool vi[Maxn];
int dfs(int S,int now[])
{
    if(vi[S]) return dp[S];
    if(S==0) return 0;
    int a[22],c[22];
    int i,j,f;
    int ans=-10000000;
    int num=0;
    vi[S]=1;
    memcpy(c,now,sizeof(c));
    for(i=0;i<b;i++){
        if((1<<i)&S){
            for(j=1;j<=g;j++){
                c[j]+=bag[i+1][j];
            }
        }
    }
    for(j=1;j<=g;j++)
        num+=c[j]/s;
    for(i=0;i<b;i++){
        if((1<<i)&S){
            f=0;
            memcpy(a,now,sizeof(a));
            for(j=1;j<=g;j++){
                a[j]+=bag[i+1][j];
                f+=a[j]/s;
                a[j]%=s;
            }
            if(f)
                ans=max(ans,f+dfs(S^(1<<i),a));
            else
                ans=max(ans,num-dfs(S^(1<<i),a));
        }
    }
    return dp[S]=ans;
}
void solve()
{
    int i,j,N;
    N=(1<<b)-1;
    dp[0]=0;
    dfs(N,now);
    int sum=0,cnt[22];
    memset(cnt,0,sizeof(cnt));
    for(i=1;i<=b;i++){
        for(j=1;j<=g;j++){
            cnt[j]+=bag[i][j];
        }
    }
    for(i=1;i<=g;i++)
        sum+=cnt[i]/s;
    printf("%d\n",2*dp[N]-sum);
}
int main()
{
    int i,j;
    while(scanf("%d%d%d",&g,&b,&s)!=EOF,g||b||s){
        memset(bag,0,sizeof(bag));
        memset(num,0,sizeof(num));
        memset(dp,-63,sizeof(dp));
        memset(vi,0,sizeof(vi));
        memset(now,0,sizeof(now));
        int x;
        for(i=1;i<=b;i++){
            scanf("%d",&num[i]);
            for(j=1;j<=num[i];j++){
                scanf("%d",&x);
                bag[i][x]++;
            }
        }
        solve();
    }
    return 0;
}

 

思路:记忆化搜索。

dp[S]表示剩下状态为S时,先手最多能得多少魔法石。

 

posted @ 2013-10-29 14:00  fangguo  阅读(287)  评论(0编辑  收藏  举报