[ABC142E] Get Everything(状压dp)

传送门

思路:

可以发现\(n\)很小,考虑状压\(dp\)
\(dp[i][j]\)表示只从前\(i\)个中选,使得集合\(j\)中的箱子都被打开花费的最小代价。
初始化:
初始化为正无穷并且\(dp[0][0]=0\)
转移:
不选第\(i\)个,从\(dp[i-1][j]\)转移过来
选第\(i\)个,转移到\(dp[i][j|b[i]]\),上一个状态为\(dp[i-1][j]\)
答案:

\[res=dp[m][(1<<n)-1] \]

细节:
为了方便状压,箱子的编号最好从\(0\)开始,将输入编号全部\(-1\)
复杂度:

\[O(m*2^{n}) \]

代码:


const int maxn=13;
ll n,m,a[1100],b[1100];
ll dp[1100][(1<<maxn)+10];
int main()
{
    n=read,m=read;
    rep(i,1,m){
        a[i]=read;
        ll t=read,x=0;
        rep(j,1,t){
            ll tmp=read;
            x|=(1<<(tmp-1));///-1是为了使得状压枚举的时候更好枚举
        }
        b[i]=x;
    }
    memset(dp,0x3f,sizeof dp);
    dp[0][0]=0;
    for(int i=1;i<=m;i++){
        for(int j=0;j<(1<<n);j++){
            dp[i][j]=min(dp[i][j],dp[i-1][j]);///不选第i个
            dp[i][j|b[i]]=min(dp[i][j|b[i]],dp[i-1][j]+a[i]);
        }
    }
    if(dp[m][(1<<n)-1]>inf/2) puts("-1");
    else cout<<dp[m][(1<<n)-1]<<endl;
    return 0;
}



posted @ 2021-05-29 11:29  OvO1  阅读(127)  评论(0编辑  收藏  举报