CF417DCunning Gena【状态压缩DP】

总感觉之前做过类似的==不出所料是一个dp,然而确实不会,一直卡在状态转移的下标怎么转化这个问题上,思维定式的以为转移就只能是+1、-1(⊙﹏⊙)b既然要求的东西是与二进制有关,那转移也这么写不就得了嘛 

再说说排序的问题,之前也考虑过要怎么找最小值的时候即考虑监视器的数又考虑给每个人的钱数~。~ 其实这里也有贪心的思想吧,最开始进行计算的是需要监视器较少的,这个结构体按照监视器的数量由小到大排序,外层循环是遍历朋友,内层循环是问题0~(limit)如果出现了问题都答了的情况更新最小值

/*************
cf417d
8228	343
GNU G++ 4.9.2
*************/
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long long INF = 4e18;
struct node
{
    int x,k,m,pro;
}fre[110];
bool cmp(node a,node b)
{
    return a.k<b.k;
}
int n,M,b;
long long dp[1050000];

int main()
{
    //freopen("cin.txt","r",stdin);
    while(~scanf("%d%d%d",&n,&M,&b))
    {
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d",&fre[i].x,&fre[i].k,&fre[i].m);
            fre[i].pro=0;
            for(int j=0;j<fre[i].m;j++)
            {
                int tmp;
                scanf("%d",&tmp);
                fre[i].pro|=(1<<(tmp-1));
            }
        }
        sort(fre,fre+n,cmp);
        memset(dp,-1,sizeof(dp));
        dp[0]=0;
        int limit=(1<<M)-1;
        long long ans=INF;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<=limit;j++)
            {
                if(dp[j]==-1) continue;
                int t=fre[i].pro|j;
                if(dp[t]!=-1) dp[t]=min(dp[j]+fre[i].x,dp[t]);
                else dp[t]=dp[j]+fre[i].x;
            }
            if(dp[limit]!=-1) ans=min(ans,dp[limit]+1LL*fre[i].k*b);
        }
        if(ans!=INF)
            printf("%lld\n",ans);
        else printf("-1\n");
    }

    return 0;
}


你可能感兴趣的:(dp,CF)