Codeforces 744C. Hongcow Buys a Deck of Cards(状压DP)

  这题的难点在于状态的设计

  首先显然是个状压,需要一维表示卡的状态,另一维如果设计成天数,难以知道当前的钱数,没法确定是否能够购买新的卡,如果设计成钱数,会发现状态数过多,空间与时间都无法承受。但是可以发现,如果没有买卡的钱会因当前卡数变化而变化这个条件的话,买卡的钱是一定的,而我们因拥有卡而省的钱不会超过120(1+2+3+...+15)。所以可以将状态设计成f[i][j]表示卡的状态为i,省了j个红币,能省多少个蓝币。

  然后就结束了...

  注意所有下标为状态的数组的大小T T...

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
const int maxn=20, inf=1e9;
int n, st, sumr, sumb, ans;
int r[maxn], b[maxn], cntr[1<<16], cntb[1<<16], f[1<<16][121];
char ch[maxn][2];
inline void read(int &k)
{
    int f=1; k=0; char c=getchar();
    while(c<'0' || c>'9') c=='-'&&(f=-1), c=getchar();
    while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
    k*=f;    
} 
int main()
{
    read(n); st=(1<<n)-1;
    for(int i=1;i<=n;i++)scanf("%s", ch[i]), read(r[i]), read(b[i]), sumr+=r[i], sumb+=b[i];
    for(int i=0;i<=st;i++)
        for(int j=1;j<=n;j++)
            if(i&(1<<(j-1)))
                cntr[i]+=(ch[j][0]=='R')?1:0, cntb[i]+=(ch[j][0]=='B')?1:0;
    memset(f,-1,sizeof(f)); f[0][0]=0;
    for(int i=0;i<=st;i++)
        for(int j=0;j<=120;j++)
            if(f[i][j]!=-1)
                for(int k=1;k<=n;k++)
                    if(!(i&(1<<(k-1))))
                    {
                        int numr=min(r[k], cntr[i]), numb=min(b[k], cntb[i]);
                        f[i|(1<<(k-1))][j+numr]=max(f[i|(1<<(k-1))][j+numr], f[i][j]+numb);
                    }
    ans=inf;
    for(int i=0;i<=120;i++)
        if(f[st][i]!=-1)
            ans=min(ans, max(sumr-i, sumb-f[st][i]));
    printf("%d
", ans+n);
}
View Code
原文地址:https://www.cnblogs.com/Sakits/p/7745871.html