codeforce 417D Cunning Gena (状压DP)

原题地址:http://codeforces.com/problemset/problem/417/D

题意:

Gena 为了解决m个问题,请他的朋友们帮忙,其中第i个朋友可以解决某mi个问题,需要花费xi卢布,并且要求安装至少ki个显示器,每个显示器需要b卢布。

问解决所有问题需要多少多少卢布

题解

考虑问题数目很小,可以状压DP。

dp[S]表示当前状态的最优解,通过位运算进行转移。

考虑|没有逆运算,所以只能正推更新。

首先把朋友按照k排序,避免k的干扰。

dp[][0]和dp[][1]分别表示考虑显示器花费和不考虑显示器花费的最小值

#include<bits/stdc++.h>

#define clr(x,y) memset((x),(y),sizeof(x))

using namespace std;
typedef long long LL;

const int maxn=(1<<20);
const LL inf=2e18;

struct Node
{
    LL x,k,m;
    int S;

    bool operator < (const Node& a) const
    {
        return k<a.k;
    }
};

LL dp[maxn+5][2];
Node f[105];

LL n,m,b;

int main(void)
{
    #ifdef ex
    freopen ("../in.txt","r",stdin);
    //freopen ("../out.txt","w",stdout);
    #endif

    scanf("%I64d%I64d%I64d",&n,&m,&b);
    for (int i=1;i<=n;++i)
    {
        scanf("%I64d%I64d%I64d",&f[i].x,&f[i].k,&f[i].m);
        int q;
        for (int j=1;j<=f[i].m;++j)
        {
            scanf("%d",&q);
            --q;
            f[i].S=f[i].S|(1<<q);
        }
    }

    sort(f+1,f+1+n);

    int S=(1<<m)-1;
    dp[0][0]=0;
    dp[0][1]=0;
    for (int i=1;i<=S;++i)
        for (int j=0;j<=1;++j)
            dp[i][j]=inf;

    for (int i=1;i<=n;++i)
    {
        //printf("%d
",f[i].S);
        for (int j=S;j>=0;--j)
        {
            if (dp[j][0]==inf) continue;
            int tS=j|f[i].S;
            dp[tS][0]=min(dp[tS][0],dp[j][0]+f[i].x);
            dp[tS][1]=min(dp[tS][1],dp[j][0]+f[i].x+f[i].k*b);

            //printf("%d %d %d
",tS,i,dp[tS][1]);
        }
    }

    if (dp[S][1]==inf) printf("-1
");
    else printf("%I64d
",dp[S][1]);
}
原文地址:https://www.cnblogs.com/123-123/p/5797028.html