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时,先手最多能得多少魔法石。

 

你可能感兴趣的:(ICPC)